diff --git a/SWIG/Source/Include/swigver.h b/SWIG/Source/Include/swigver.h new file mode 100644 index 000000000..b76110b9d --- /dev/null +++ b/SWIG/Source/Include/swigver.h @@ -0,0 +1,7 @@ + +/* SWIG version information */ + +#define SWIG_MAJOR_VERSION 1 +#define SWIG_MINOR_VERSION 3 +#define SWIG_SPIN "(Beta 1)" + diff --git a/SWIG/Source/Modules1.1/Makefile.in b/SWIG/Source/Modules1.1/Makefile.in new file mode 100644 index 000000000..737fd6cc6 --- /dev/null +++ b/SWIG/Source/Modules1.1/Makefile.in @@ -0,0 +1,59 @@ +####################################################################### +# $Header$ +# Simplified Wrapper and Interface Generator (SWIG) +# +####################################################################### + +#.KEEP_STATE: + + +srcdir = @srcdir@ +VPATH = @srcdir@ + +# Set your C++ compiler here. g++ works on most machines, +# but you might have to change it depending on your installation. +# +CC = @CXX@ + +# +# Set the prefix below to indicate where you want SWIG to install its +# files. Normally this is /usr/local +# + +prefix = @prefix@ + +# Location of the SWIG library. Is normally put in /usr/local/lib/swig_lib +# The SWIG library contains configuration files and library modules +# so you should install it someplace where it can be easily accessed. + +SWIG_LIB = $(prefix)/lib/swig1.3 + +######################################################################## +# Normally, you shouldn't have to change anything below this point # +######################################################################## + +WRAPOBJS = swigmain.o tcl8.o perl5.o python.o pycpp.o guile.o debug.o +WRAPSRCS = swigmain.cxx tcl8.cxx perl5.cxx python.cxx pycpp.cxx guile.cxx debug.cxx + +TARGET = ../swig +CFLAGS = @CFLAGS@ -DSWIG_LIB='"$(SWIG_LIB)"' -DSWIG_CC='"$(CC)"' @DEFS@ +INCLUDE = -I../Include -I../SWIG1.1 +SHELL = /bin/sh + +# +# +# +# Rules for creation of a .o file from .cxx +.SUFFIXES: .cxx +.cxx.o: + $(CC) $(INCLUDE) $(CFLAGS) -c -o $*.o $< + +all: $(TARGET) + +$(TARGET): $(WRAPOBJS) + +clean:: + rm -f *.o *~ + +nuke:: + rm -f Makefile *~ #* core a.out diff --git a/SWIG/Source/Modules1.1/debug.cxx b/SWIG/Source/Modules1.1/debug.cxx new file mode 100644 index 000000000..10f2805bc --- /dev/null +++ b/SWIG/Source/Modules1.1/debug.cxx @@ -0,0 +1,198 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/************************************************************************** + * $Header$ + * + * debug.cxx + * + * This is a dummy language module that is used only for testing the SWIG + * parser. + * + * It creates a wrapper file, but only containing descriptions of what + * was wrapped. + * + ***************************************************************************/ + +#include "swig.h" +#include "debug.h" + +void DEBUGLANG::parse_args(int, char **) { + sprintf(LibDir,"%s",path); + typemap_lang = "debug"; +} + +void DEBUGLANG::parse() { + headers(); + yyparse(); +} + +void DEBUGLANG::set_module(char *mod_name, char **) { + if (module) return; + module = new char[strlen(mod_name)+1]; + strcpy(module,mod_name); +} + +void DEBUGLANG::set_init(char *init_name) { + set_module(init_name,0); +} + +void DEBUGLANG::headers(void) { + fprintf(f_header,"/* DEBUG : Language specific headers go here */\n\n"); + fprintf(f_header,"/* DEBUG : Pointer conversion function here */\n\n"); + fprintf(f_header,"/* DEBUG : Language specific code here */\n\n"); +} + +void DEBUGLANG::initialize(void) { + + fprintf(f_header,"#define SWIG_init %s_init\n\n", module); + fprintf(f_header,"#define SWIG_name \"%s\"\n", module); + + fprintf(f_init,"\n/* MODULE INITIALIZATION */\n\n"); + fprintf(f_init,"void %s_init() {\n", module); + +} + +void DEBUGLANG::close(void) { + fprintf(f_init,"} /* END INIT */\n"); + + fprintf(f_wrappers,"SWIG POINTER-MAPPING TABLE\n\n"); + emit_ptr_equivalence(f_init); +} + +void DEBUGLANG::create_function(char *name, char *iname, DataType *d, ParmList *l) { + + fprintf(f_wrappers,"WRAPPER : "); + emit_extern_func(name,d,l,0,f_wrappers); + fprintf(f_wrappers,"\n"); + + fprintf(f_init," ADD COMMAND : %s --> ", iname); + emit_extern_func(name,d,l,0,f_init); + +} + +void DEBUGLANG::link_variable(char *name, char *iname, DataType *t) { + fprintf(f_wrappers,"WRAPPER : "); + emit_extern_var(name,t,0,f_wrappers); + + fprintf(f_init," ADD VARIABLE : %s --> ", iname); + emit_extern_var(name,t,0,f_init); + +} + +void DEBUGLANG::declare_const(char *name, char *, DataType *type, char *value) { + if (!value) value = "[None]"; + fprintf(f_init," ADD CONSTANT : %s %s = %s\n", type->print_cast(),name,value); +} + +void DEBUGLANG::add_native(char *name, char *funcname) { + fprintf(f_init," ADD NATIVE : %s --> %s\n", name, funcname); +} + +void DEBUGLANG::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) { + fprintf(f_wrappers," MEMBER FUNC : "); + emit_extern_func(name,t,l,0,f_wrappers); + fprintf(f_wrappers,"\n"); + if (!iname) iname = name; + fprintf(f_init," ADD MEMBER FUN : %s --> ", iname); + emit_extern_func(name,t,l,0,f_init); +} + +void DEBUGLANG::cpp_constructor(char *name, char *iname, ParmList *l) { + DataType *t; + fprintf(f_wrappers," CONSTRUCTOR : "); + t = new DataType(T_USER); + sprintf(t->name,"%s",name); + t->is_pointer=1; + emit_extern_func(name,t,l,0,f_wrappers); + if (!iname) iname = name; + fprintf(f_init," ADD CONSTRUCT : %s --> ", iname); + emit_extern_func(name,t,l,0,f_init); +} + +void DEBUGLANG::cpp_destructor(char *name, char *iname) { + fprintf(f_wrappers," DESTRUCTOR : ~%s();\n", name); + if (!iname) iname = name; + fprintf(f_init," ADD DESTRUCT : %s --> ~%s();\n",iname,name); +} + +void DEBUGLANG::cpp_open_class(char *name, char *iname, char *ctype, int strip) { + this->Language::cpp_open_class(name, iname, ctype,strip); + fprintf(f_wrappers,"C++ CLASS START : %s %s ========================================\n\n",ctype,name); + fprintf(f_init,"\n // C++ CLASS START : %s %s\n",ctype,name); +} + +void DEBUGLANG::cpp_close_class() { + fprintf(f_wrappers,"C++ CLASS END ===================================================\n\n"); + fprintf(f_init," // C++ CLASS END \n\n"); +} + +void DEBUGLANG::cpp_inherit(char **baseclass, int) { + int i = 0; + if (baseclass) { + fprintf(f_wrappers,"inheriting from baseclass :"); + while (baseclass[i]) { + fprintf(f_wrappers," %s",baseclass[i]); + i++; + } + fprintf(f_wrappers,"\n"); + } + this->Language::cpp_inherit(baseclass); +} + +void DEBUGLANG::cpp_variable(char *name, char *iname, DataType *t) { + fprintf(f_wrappers," ATTRIBUTE : "); + emit_extern_var(name,t,0,f_wrappers); + if (!iname) iname = name; + fprintf(f_init," ADD MEMBER : %s --> ", iname); + emit_extern_var(name,t,0,f_init); +} +void DEBUGLANG::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) { + + fprintf(f_wrappers," STATIC FUNC : "); + emit_extern_func(name,t,l,0,f_wrappers); + fprintf(f_init," ADD STATIC FUNC: %s --> ", iname); + emit_extern_func(name,t,l,0,f_init); + +} + +void DEBUGLANG::cpp_declare_const(char *name, char *iname, DataType *t, char *value) { + if (!value) value = "[None]"; + fprintf(f_wrappers," C++ CONST : %s %s = %s\n", t->print_cast(), name, value); + if (!iname) iname = name; + fprintf(f_init," ADD C++ CONST : %s --> %s = %s\n", iname, t->print_cast(), value); +} + +void DEBUGLANG::cpp_static_var(char *name, char *iname, DataType *t) { + fprintf(f_wrappers," C++ STATIC VAR: "); + emit_extern_var(name,t,0,f_wrappers); + if (!iname) iname = name; + fprintf(f_init," ADD STATIC VAR : %s --> ",iname); + emit_extern_var(name,t,0,f_init); +} + +void DEBUGLANG::pragma(char *lname, char *name, char *value) { + fprintf(f_wrappers,"PRAGMA : LANG = %s, NAME = %s ", lname, name); + if (value) { + fprintf(f_wrappers,", VALUE = %s\n", value); + } else { + fprintf(f_wrappers,"\n"); + } +} + +void DEBUGLANG::cpp_class_decl(char *name, char *, char *type) { + fprintf(f_wrappers,"C++ CLASS DECLARATION : %s %s\n", type,name); +} + + diff --git a/SWIG/Source/Modules1.1/debug.h b/SWIG/Source/Modules1.1/debug.h new file mode 100644 index 000000000..1a0f8dd03 --- /dev/null +++ b/SWIG/Source/Modules1.1/debug.h @@ -0,0 +1,52 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +class DEBUGLANG : public Language { +private: + char *path; + char *module; +public: + DEBUGLANG() { + path = "debug"; + module = "swig"; + } + void parse_args(int argc, char *argv[]); + void parse(); + void create_function(char *, char *, DataType *, ParmList *); + void link_variable(char *, char *, DataType *) ; + void declare_const(char *, char *, DataType *, char *); + void initialize(void); + void headers(void); + void close(void); + void set_module(char *mod_name, char **mod_list); + void set_init(char *init_name); + void add_native(char *, char *); + char *type_mangle(DataType *t) { + return t->print_mangle_default(); + } + void cpp_member_func(char *, char *, DataType *, ParmList *); + void cpp_constructor(char *, char *, ParmList *); + void cpp_destructor(char *, char *); + void cpp_open_class(char *, char *, char *, int strip); + void cpp_close_class(); + void cpp_inherit(char **, int mode = INHERIT_ALL); + void cpp_variable(char *, char *, DataType *); + void cpp_static_func(char *, char *, DataType *, ParmList *); + void cpp_declare_const(char *, char *, DataType *, char *); + void cpp_static_var(char *, char *, DataType *); + void pragma(char *, char *, char *); + void cpp_class_decl(char *, char *, char *); + +}; diff --git a/SWIG/Source/Modules1.1/guile.cxx b/SWIG/Source/Modules1.1/guile.cxx new file mode 100644 index 000000000..36a00a307 --- /dev/null +++ b/SWIG/Source/Modules1.1/guile.cxx @@ -0,0 +1,841 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * guile.cxx + * + * Definitions for adding functions to Guile 3.0 + ***********************************************************************/ + +#include "swig.h" +#include "guile.h" + +static char *guile_usage = "\ +Guile Options (available with -guile)\n\ + None available. \n\n"; + +// --------------------------------------------------------------------- +// GUILE::parse_args(int argc, char *argv[]) +// +// Parse arguments. +// --------------------------------------------------------------------- + +void GUILE::parse_args(int argc, char *argv[]) { + + int i; + + sprintf(LibDir,"%s",guile_path); + + // Look for certain command line options + + // Look for additional command line options. + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-help") == 0) { + fputs(guile_usage,stderr); + SWIG_exit(0); + } + } + } + // Add a symbol for this module + + add_symbol("SWIGGUILE",0,0); + + // Set name of typemaps + + typemap_lang = "guile"; + +} + +// -------------------------------------------------------------------- +// GUILE::parse() +// +// Parse the input file +// -------------------------------------------------------------------- + +void GUILE::parse() +{ + + printf("Generating wrappers for Guile\n"); + + // Print out GUILE specific headers + + headers(); + + // Run the parser + + yyparse(); + +} + +// --------------------------------------------------------------------- +// GUILE::set_module(char *mod_name) +// +// Sets the module name. +// Does nothing if it's already set (so it can be overridden as a command +// line option). +// +//---------------------------------------------------------------------- + +void GUILE::set_module(char *mod_name, char **) { + + if (module) return; + + module = new char[strlen(mod_name)+1]; + strcpy(module,mod_name); + +} + +// --------------------------------------------------------------------- +// GUILE::set_init(char *iname) +// +// Sets the initialization function name. +// Does nothing if it's already set +// +//---------------------------------------------------------------------- + +void GUILE::set_init(char *iname) { + set_module(iname,0); +} + +// --------------------------------------------------------------------- +// GUILE::headers(void) +// +// Generate the appropriate header files for GUILE interface. +// ---------------------------------------------------------------------- + +void GUILE::headers(void) +{ + + emit_banner(f_header); + + fprintf(f_header,"/* Implementation : GUILE */\n\n"); + fprintf(f_header,"#define SWIGGUILE\n"); + fprintf(f_header,"#include \n"); + fprintf(f_header,"#include \n"); + fprintf(f_header,"#include \n"); + + // Write out hex conversion functions + + if (!NoInclude) { + if (insert_file("guile.swg", f_header) == -1) { + fprintf(stderr,"SWIG : Fatal error. Unable to locate 'guile.swg' in SWIG library.\n"); + SWIG_exit(1); + } + emit_hex(f_header); + } else { + fprintf(f_header,"#ifdef __cplusplus\n"); + fprintf(f_header,"extern \"C\" {\n"); + fprintf(f_header,"#endif\n"); + fprintf(f_header,"extern void SWIG_MakePtr(char *, void *, char *);\n"); + fprintf(f_header,"extern void SWIG_RegisterMapping(char *, char *, void *(*)(void *));\n"); + fprintf(f_header,"extern char *SWIG_GetPtr(char *, void **, char *);\n"); + fprintf(f_header,"#ifdef __cplusplus\n"); + fprintf(f_header,"}\n"); + fprintf(f_header,"#endif\n"); + } +} + +// -------------------------------------------------------------------- +// GUILE::initialize() +// +// Output initialization code that registers functions with the +// interface. +// --------------------------------------------------------------------- +void GUILE::initialize() +{ + + int i; + + if (!module) { + module = "swig_init"; + fprintf(stderr,"SWIG : *** Warning. No module name specified.\n"); + } + + fprintf(f_header,"#define SWIG_init %s\n\n", module); + fprintf(f_init,"void %s() {\n", module); + + if (InitNames) { + i = 0; + while (InitNames[i]) { + fprintf(f_init,"\t %s();\n",InitNames[i]); + i++; + } + } +} + +// --------------------------------------------------------------------- +// GUILE::close(void) +// +// Wrap things up. Close initialization function. +// --------------------------------------------------------------------- + +void GUILE::close(void) +{ + + emit_ptr_equivalence(f_init); + fprintf(f_init,"}\n"); + +} + +// ---------------------------------------------------------------------- +// GUILE::get_pointer(int parm, DataType *t) +// +// Emits code to get a pointer from a parameter and do type checking. +// parm is the parameter number. This function is only used +// in create_function(). +// ---------------------------------------------------------------------- + +void GUILE::get_pointer(char *iname, int parm, DataType *t) { + + // Pointers are read as hex-strings with encoded type information + fprintf(f_wrappers,"\t _tempc = gh_scm2newstr(s_%d, &_len);\n",parm); + fprintf(f_wrappers,"\t if (SWIG_GetPtr(_tempc, (void **) &_arg%d,",parm); + if (t->type == T_VOID) fprintf(f_wrappers,"(char *) 0)) {\n"); + else + fprintf(f_wrappers,"\"%s\")) {\n", t->print_mangle()); + + // Now emit code according to the level of strictness desired + + switch(TypeStrict) { + case 0: // No type checking + fprintf(f_wrappers,"\t}\n"); + break; + case 1: // Warning message only + fprintf(f_wrappers, + "\t fprintf(stderr,\"Warning : type mismatch in argument %d of %s. Expected %s, received %%s\\n\", _tempc);\n", parm+1,iname, t->print_mangle()); + fprintf(f_wrappers,"\t }\n"); + break; + case 2: // Super strict mode. + +// fprintf(f_wrappers,"\t\t gscm_error(\"Type error in argument %d of %s. Expected %s.\", s_%d);\n", parm+1,iname,t->print_mangle(),parm); + fprintf(f_wrappers,"\t}\n"); + break; + + default : + fprintf(stderr,"Unknown strictness level\n"); + break; + } +} + +// ---------------------------------------------------------------------- +// GUILE::create_function(char *name, char *iname, DataType *d, +// ParmList *l) +// +// Create a function declaration and register it with the interpreter. +// ---------------------------------------------------------------------- + +void GUILE::create_function(char *name, char *iname, DataType *d, ParmList *l) +{ + + Parm *p; + int pcount; + char wname[256]; + char source[64]; + char target[64]; + char *tm; + String cleanup; + int need_len = 0; + int need_tempc = 0; + + // Make a wrapper name for this + + strcpy(wname,iname); + make_wrap_name(wname); + + // Now write the wrapper function itself....this is pretty ugly + + fprintf(f_wrappers,"SCM _wrap_gscm_%s(",wname); + + int i = 0; + p = l->get_first(); + while (p != 0) { + if (p->t->is_pointer) + need_len = 1; + if ((p->t->type != T_CHAR) && (p->t->is_pointer)) + need_tempc = 1; + + if ((p->t->type != T_VOID) || (p->t->is_pointer)) + fprintf(f_wrappers,"SCM s_%d", i); + if ((p = l->get_next())) + fprintf(f_wrappers,", "); + i++; + } + fprintf(f_wrappers,")\n{\n"); + + // Declare return variable and arguments + + pcount = emit_args(d,l,f_wrappers); + + // Now declare a few helper variables here + if (d->is_pointer && (d->type != T_CHAR) && + !typemap_lookup("out","guile",d,name,"_result","scmresult")) + fprintf(f_wrappers," char _ptemp[128];\n"); + if (need_tempc) + fprintf(f_wrappers," char *_tempc;\n"); + if (need_len) + fprintf(f_wrappers," int _len;\n"); + fprintf(f_wrappers," SCM scmresult; /* fun1 */\n"); + + // Now write code to extract the parameters(this is super ugly) + + i = 0; + p = l->get_first(); + while (p != 0) { + // Produce names of source and target + sprintf(source,"s_%d",i); + sprintf(target,"_arg%d",i); + + if ((tm = typemap_lookup("in","guile",p->t,p->name,source,target))) { + // Yep. Use it instead of the default + fprintf(f_wrappers,"%s\n", tm); + } else { + if (!p->t->is_pointer) { + switch(p->t->type) { + + // Signed Integers + + case T_INT : + case T_SINT : + case T_SHORT: + case T_SSHORT: + case T_LONG: + case T_SLONG: + case T_SCHAR: + fprintf(f_wrappers,"\t _arg%d = %s gh_scm2long(s_%d);\n",i, p->t->print_cast(), i); + break; + + // Unsigned Integers + + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + fprintf(f_wrappers,"\t _arg%d = %s gh_scm2ulong(s_%d);\n", i, p->t->print_cast(), i); + break; + + // A single character + + case T_CHAR : + fprintf(f_wrappers,"\t _arg%d = %s gh_scm2char(s_%d);\n", i, p->t->print_cast(), i); + break; + + // Floating point + + case T_DOUBLE : + case T_FLOAT: + fprintf(f_wrappers,"\t _arg%d = %s gh_scm2double(s_%d);\n", i, p->t->print_cast(), i); + break; + + // Void.. Do nothing. + + case T_VOID : + break; + + // This is some sort of user-defined call by value type. We're + // going to try and wing it here.... + + case T_USER: + + // User defined type not allowed by value. + + default : + fprintf(stderr,"%s : Line %d. Unable to use type %s as a function argument.\n", + input_file, line_number, p->t->print_type()); + break; + } + } else { + + // Argument is a pointer type. Special case is for char * + // since that is usually a string. + + if ((p->t->type == T_CHAR) && (p->t->is_pointer == 1)) { + fprintf(f_wrappers,"\t _arg%d = gh_scm2newstr(s_%d, &_len);\n",i,i); + } else { + + // Have a generic pointer type here. + + get_pointer(iname, i, p->t); + } + } + } + if ((tm = typemap_lookup("check","guile",p->t,p->name,source,target))) { + // Yep. Use it instead of the default + fprintf(f_wrappers,"%s\n",tm); + } + if ((tm = typemap_lookup("freearg","guile",p->t,p->name,target,"scmresult"))) { + // Yep. Use it instead of the default + cleanup << tm << "\n"; + } + p = l->get_next(); + i++; + } + + // Now write code to make the function call + + fprintf(f_wrappers,"\t SCM_DEFER_INTS;\n"); + emit_func_call(name,d,l,f_wrappers); + + fprintf(f_wrappers,"\t SCM_ALLOW_INTS;\n"); + // Now have return value, figure out what to do with it. + + if ((d->type != T_VOID) || (d->is_pointer)) { + if ((tm = typemap_lookup("out","guile",d,name,"_result","scmresult"))) { + // Yep. Use it instead of the default + fprintf(f_wrappers,"%s\n",tm); + } else { + if (!d->is_pointer) { + switch(d->type) { + case T_INT: case T_SINT: + case T_SHORT: case T_SSHORT: + case T_LONG: case T_SLONG: + case T_SCHAR: + fprintf(f_wrappers,"\t scmresult = gh_long2scm((long) _result);\n"); + break; + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + fprintf(f_wrappers,"\t scmresult = gh_ulong2scm((unsigned long) _result);\n"); + break; + case T_DOUBLE : + case T_FLOAT: + fprintf(f_wrappers,"\t scmresult = gh_double2scm((double) _result);\n"); + break; + case T_CHAR : + fprintf(f_wrappers,"\t scmresult = gh_char2scm(_result);\n"); + break; + default: + fprintf(stderr,"%s : Line %d: Unable to use return type %s in function %s.\n", + input_file, line_number, d->print_type(), name); + break; + } + } else { + + // Is a pointer return type + + if ((d->type == T_CHAR) && (d->is_pointer == 1)) { + fprintf(f_wrappers,"\t scmresult = gh_str02scm(_result);\n"); + } else { + + // Is an ordinary pointer type. + + fprintf(f_wrappers,"\t SWIG_MakePtr(_ptemp, _result,\"%s\");\n", + d->print_mangle()); + fprintf(f_wrappers,"\t scmresult = gh_str02scm(_ptemp);\n"); + } + } + } + } else { + /* Some void type. Need to return something. I'll return 1 */ + fprintf(f_wrappers,"\t scmresult = gh_int2scm(1);\n"); + } + + // Dump the argument cleanup code + fprintf(f_wrappers,"%s\n",cleanup.get()); + + // Look for any remaining cleanup + + if (NewObject) { + if ((tm = typemap_lookup("newfree","guile",d,iname,"_result",""))) { + fprintf(f_wrappers,"%s\n",tm); + } + } + + if ((tm = typemap_lookup("ret","guile",d,name,"_result",""))) { + // Yep. Use it instead of the default + fprintf(f_wrappers,"%s\n",tm); + } + + // Wrap things up (in a manner of speaking) + + fprintf(f_wrappers,"\t return scmresult;\n"); + fprintf(f_wrappers,"}\n"); + + // Now register the function + fprintf(f_init,"\t gh_new_procedure(\"%s\", _wrap_gscm_%s, %d, 0, 0);\n", + iname, wname, pcount); + + // Make a documentation entry for this + + if (doc_entry) { + static DocEntry *last_doc_entry = 0; + char *usage = 0; + usage_func(iname,d,l,&usage); + doc_entry->usage << usage; + if (last_doc_entry != doc_entry) { + doc_entry->cinfo << "returns " << d->print_type(); + last_doc_entry = doc_entry; + } + delete usage; + } +} + +// ----------------------------------------------------------------------- +// GUILE::link_variable(char *name, char *iname, DataType *d) +// +// Create a link to a C variable. +// This creates a single function _wrap_gscm_var_varname(). +// This function takes a single optional argument. If supplied, it means +// we are setting this variable to some value. If ommitted, it means we are +// simply evaluating this variable. Either way, we return the variables +// value. +// ----------------------------------------------------------------------- + +void GUILE::link_variable(char *name, char *iname, DataType *t) +{ + + char var_name[256]; + char *tm; + char *tm2 = typemap_lookup("varout","guile",t,name,name,"scmresult"); + + // evaluation function names + + sprintf(var_name,"_wrap_gscm_var_%s",iname); + + if ((t->type != T_USER) || (t->is_pointer)) { + + fprintf(f_wrappers,"SCM %s(SCM s_0) {\n", var_name); + + if (!(Status & STAT_READONLY) && (t->is_pointer)) { + fprintf(f_wrappers,"\t char *_temp;\n"); + fprintf(f_wrappers,"\t int _len;\n"); + } + + if (tm2) { + fprintf(f_wrappers,"\t char _ptemp[128];\n"); + } + fprintf(f_wrappers,"\t SCM scmresult; /* fun2 */\n"); + + // Check for a setting of the variable value + + fprintf(f_wrappers,"\t if (s_0 != GH_NOT_PASSED) {\n"); + + // Yup. Extract the type from s_0 and set variable value + if (Status & STAT_READONLY) { +// fprintf(f_wrappers,"\t\t gscm_error(\"Unable to set %s. Variable is read only.\", s_0);\n", iname); + } else { + if ((tm = typemap_lookup("varin","guile",t,name,"s_0",name))) { + // Yep. Use it instead of the default + fprintf(f_wrappers,"%s\n",tm); + } else { + if (!t->is_pointer) { + + switch(t->type) { + // Signed Integer + + case T_INT: case T_SINT: + case T_SHORT: case T_SSHORT: + case T_LONG: case T_SLONG: + case T_SCHAR: + fprintf(f_wrappers,"\t\t %s = %s gh_scm2long(s_0);\n",name, t->print_cast()); + break; + + // Unsigned integer + + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + fprintf(f_wrappers,"\t\t %s = %s gh_scm2ulong(s_0);\n",name, t->print_cast()); + break; + + // Floating point + + case T_FLOAT: + case T_DOUBLE: + fprintf(f_wrappers,"\t\t %s = %s gh_scm2double(s_0);\n",name, t->print_cast()); + break; + + // Character value + + case T_CHAR: + fprintf(f_wrappers,"\t\t %s = gh_scm2char(s_0);\n", name); + break; + + // Unknown value + + default: + fprintf(stderr,"Line %d. Error, unsupported data-type.\n", line_number); + break; + } + } else { + + // Have some sort of pointer type here, Process it differently + + if ((t->type == T_CHAR) && (t->is_pointer == 1)) { + fprintf(f_wrappers,"\t\t _temp = gh_scm2newstr(s_0, &_len);\n"); + fprintf(f_wrappers,"\t\t if (%s) { free(%s);}\n", name,name); + fprintf(f_wrappers,"\t\t %s = (char *) malloc((_len+1)*sizeof(char));\n",name); + fprintf(f_wrappers,"\t\t strncpy(%s,_temp,_len);\n",name); + fprintf(f_wrappers,"\t\t %s[_len] = 0;\n", name); + } else { + // Set the value of a pointer + fprintf(f_wrappers,"\t\t _temp = gh_scm2newstr(s_0,&_len);\n"); + fprintf(f_wrappers,"\t if (SWIG_GetPtr(_temp, (void **) &%s,",name); + if (t->type == T_VOID) fprintf(f_wrappers,"(char *) 0)) {\n"); + else + fprintf(f_wrappers,"\"%s\")) {\n", t->print_mangle()); + + // Now emit code according to the level of strictness desired + + switch(TypeStrict) { + case 0: // No type checking + fprintf(f_wrappers,"\t}\n"); + break; + case 1: // Warning message only + fprintf(f_wrappers, + "\t fprintf(stderr,\"Warning : type mismatch in variable %s. Expected %s, received %%s\\n\", _temp);\n", name, t->print_mangle()); + fprintf(f_wrappers,"\t }\n"); + break; + case 2: // Super strict mode. + +// fprintf(f_wrappers,"\t\t gscm_error(\"Type error in variable %s. Expected %s.\", s_0);\n", name,t->print_mangle()); + fprintf(f_wrappers,"\t}\n"); + break; + + default : + fprintf(stderr,"Unknown strictness level\n"); + break; + } + } + } + } + } + fprintf(f_wrappers,"\t}\n"); + + // Now return the value of the variable (regardless of evaluating or setting) + + if (tm2) { + // Yep. Use it instead of the default + fprintf(f_wrappers,"%s\n",tm); + } else { + if (!t->is_pointer) { + /* Return variable by value */ + + switch(t->type) { + + // Signed Integer + + case T_INT: case T_SINT: + case T_SHORT: case T_SSHORT: + case T_LONG: case T_SLONG: + case T_SCHAR: + fprintf(f_wrappers,"\t scmresult = gh_long2scm((long) %s);\n", name); + break; + + // Unsigned integer + + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + fprintf(f_wrappers,"\t scmresult = gh_ulong2scm((unsigned long) %s);\n",name); + break; + + // Floats + + case T_DOUBLE: + case T_FLOAT: + fprintf(f_wrappers,"\t scmresult = gh_double2scm((double) %s);\n", name); + break; + case T_CHAR: + fprintf(f_wrappers,"\t scmresult = gh_char2scm(%s);\n",name); + break; + default : + /* Unknown type */ + break; + } + } else { + + // Is a pointer return type + + if ((t->type == T_CHAR) && (t->is_pointer == 1)) { + fprintf(f_wrappers,"\t scmresult = gh_str02scm(%s);\n",name); + } else { + // Is an ordinary pointer type. + fprintf(f_wrappers,"\t SWIG_MakePtr(_ptemp, %s,\"%s\");\n",name, + t->print_mangle()); + fprintf(f_wrappers,"\t scmresult = gh_str02scm(_ptemp);\n"); + } + } + } + fprintf(f_wrappers,"\t return scmresult;\n"); + fprintf(f_wrappers,"}\n"); + + // Now add symbol to the Guile interpreter + + fprintf(f_init,"\t gh_new_procedure(\"%s\", %s, 0, 1, 0);\n",iname, var_name); + + } else { + fprintf(stderr,"%s : Line %d. ** Warning. Unable to link with type %s (ignored).\n", + input_file, line_number, t->print_type()); + } + + // Add a documentation entry + + if (doc_entry) { + char *usage = 0; + usage_var(iname,t,&usage); + doc_entry->usage << usage; + doc_entry->cinfo << "Global : " << t->print_type() << " " << name; + delete usage; + } + +} + +// ----------------------------------------------------------------------- +// GUILE::declare_const(char *name, char *iname, DataType *type, char *value) +// +// Makes a constant. Not sure how this is really supposed to work. +// I'm going to fake out SWIG and create a variable instead. +// ------------------------------------------------------------------------ + +void GUILE::declare_const(char *name, char *, DataType *type, char *value) { + + int OldStatus = Status; // Save old status flags + char var_name[256]; + + Status = STAT_READONLY; // Enable readonly mode. + + // Make a static variable; + + sprintf(var_name,"_wrap_const_%s",name); + + if ((type->type == T_USER) && (!type->is_pointer)) { + fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number); + return; + } + + // Create variable and assign it a value + + fprintf(f_header,"static %s %s = ", type->print_type(), var_name); + if ((type->type == T_CHAR) && (type->is_pointer <= 1)) { + fprintf(f_header,"\"%s\";\n", value); + } else { + fprintf(f_header,"%s;\n", value); + } + + // Now create a variable declaration + + link_variable(var_name, name, type); + Status = OldStatus; + + if (doc_entry) { + char *usage = 0; + usage_const(name,type,value,&usage); + doc_entry->usage = ""; + doc_entry->usage << usage; + doc_entry->cinfo = ""; + doc_entry->cinfo << "Constant: " << type->print_type(); + delete usage; + } + +} + +// ---------------------------------------------------------------------- +// GUILE::usage_var(char *iname, DataType *t, char **s) +// +// Produces a usage string for a Guile variable. +// ---------------------------------------------------------------------- + +void GUILE::usage_var(char *iname, DataType *t, char **s) { + + char temp[1024], *c; + + sprintf(temp,"(%s)", iname); + c = temp + strlen(temp); + + if (!((t->type != T_USER) || (t->is_pointer))) { + sprintf(c," - unsupported"); + } + + if (*s == 0) + *s = new char[strlen(temp)+1]; + strcpy(*s,temp); +} + +// --------------------------------------------------------------------------- +// GUILE::usage_func(char *iname, DataType *t, ParmList *l, char **s) +// +// Produces a usage string for a function in Guile +// --------------------------------------------------------------------------- + +void GUILE::usage_func(char *iname, DataType *, ParmList *l, + char **s) { + + char temp[1024]; + char *c; + int i; + Parm *p; + + sprintf(temp,"(%s ", iname); + c = temp + strlen(temp); + + /* Now go through and print parameters */ + + p = l->get_first(); + while (p != 0) { + + /* If parameter has been named, use that. Otherwise, just print a type */ + + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + if (strlen(p->name) > 0) { + sprintf(c,"%s ",p->name); + c += strlen(p->name)+1; + } + else { + sprintf(c,"%s",p->t->name); + c += strlen(p->t->name); + if (p->t->is_pointer) { + for (i = 0; i < (p->t->is_pointer-p->t->implicit_ptr); i++) { + sprintf(c,"*"); + c++; + } + } + } + } + p = l->get_next(); + if (p != 0) { + sprintf(c," "); + c++; + } + } + sprintf(c,")"); + if (*s == 0) + *s = new char[strlen(temp)+1]; + strcpy(*s,temp); +} + + +// ---------------------------------------------------------------------- +// GUILE::usage_const(char *iname, DataType *type, char *value, char **s) +// +// Produces a usage string for a Guile constant +// ---------------------------------------------------------------------- + +void GUILE::usage_const(char *iname, DataType *, char *value, char **s) { + + char temp[1024]; + + sprintf(temp,"(%s %s)", iname, value); + + if (*s == 0) + *s = new char[strlen(temp)+1]; + strcpy(*s,temp); + +} diff --git a/SWIG/Source/Modules1.1/guile.h b/SWIG/Source/Modules1.1/guile.h new file mode 100644 index 000000000..ffde1c4a2 --- /dev/null +++ b/SWIG/Source/Modules1.1/guile.h @@ -0,0 +1,57 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/************************************************************************** + * $Header$ + * + * class GUILE + * + * Guile implementation + * (Caution : This is *somewhat* experimental) + * + * Seeking : highly motivated individual with plenty of spare time and + * a love of Guile. Must be willing to modify this code and + * make it better. + **************************************************************************/ + +class GUILE : public Language { +private: + char *guile_path; + char *module; + void get_pointer(char *iname, int parm, DataType *t); + void usage_var(char *, DataType *, char **); + void usage_func(char *, DataType *, ParmList *, char **); + void usage_const(char *, DataType *, char *, char **); +public : + GUILE() { + module = 0; + guile_path = "guile"; + } + void parse_args(int, char *argv[]); + void parse(); + void create_function(char *, char *, DataType *, ParmList *); + void link_variable(char *, char *, DataType *); + void declare_const(char *, char *, DataType *, char *); + void initialize(); + void headers(void); + void close(void); + void set_module(char *, char **); + void set_init(char *); + void create_command(char *, char *) { }; +}; + + + + diff --git a/SWIG/Source/Modules1.1/perl5.cxx b/SWIG/Source/Modules1.1/perl5.cxx new file mode 100644 index 000000000..daa00a651 --- /dev/null +++ b/SWIG/Source/Modules1.1/perl5.cxx @@ -0,0 +1,2327 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * perl5.c + * + * Definitions for adding functions to Perl 5 + * + * How to extend perl5 (note : this is totally different in Perl 4) : + * + * 1. Variable linkage + * + * Must declare two functions : + * + * _var_set(SV *sv, MAGIC *mg); + * _var_get(SV *sv, MAGIC *mg); + * + * These functions must set/get the values of a variable using + * Perl5 internals. + * + * To add these to Perl5 (which isn't entirely clear), need to + * do the following : + * + * SV *sv; + * MAGIC *m; + * sv = perl_get_sv("varname",TRUE); + * sv_magic(sv,sv, 'U', "varname", strlen("varname)); + * m = mg_find(sv, 'U'); + * m->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL)); + * m->mg_virtual.svt_get = _var_set; + * m->mg_virtual.svt_set = _var_get; + * m->mg_virtual.svt_len = 0; + * m->mg_virtual.svt_free = 0; + * m->mg_virtual.svt_clear = 0; + * + * + * 2. Function extension + * + * Functions are declared as : + * XS(_wrap_func) { + * dXSARGS; + * if (items != parmcount) { + * croak("Usage :"); + * } + * ... get arguments ... + * + * ... call function ... + * ... set return value in ST(0) + * XSRETURN(1); + * } + * To extract function arguments, use the following : + * _arg = (int) SvIV(ST(0)) + * _arg = (double) SvNV(ST(0)) + * _arg = (char *) SvPV(ST(0),na); + * + * For return values, use : + * ST(0) = sv_newmortal(); + * sv_setiv(ST(0), (IV) RETVAL); // Integers + * sv_setnv(ST(0), (double) RETVAL); // Doubles + * sv_setpv((SV*) ST(0), RETVAL); // Strings + * + * New functions are added using + * newXS("name", _wrap_func, file) + * + * + * 3. Compilation. + * + * Code should be compiled into an object file for dynamic + * loading into Perl. + ***********************************************************************/ + +#include "swig.h" +#include "perl5.h" + +static String pragma_include; + +static char *usage = "\ +Perl5 Options (available with -perl5)\n\ + -module name - Set module name\n\ + -package name - Set package prefix\n\ + -hide name - Set hide package name.\n\ + -static - Omit code related to dynamic loading.\n\ + -shadow - Create shadow classes.\n\ + -compat - Compatibility mode.\n\ + -alt-header file- Use an alternate header.\n\n"; + +static char *import_file = 0; +static char *smodule = 0; +static int compat = 0; + +// --------------------------------------------------------------------- +// PERL5::parse_args(int argc, char *argv[]) +// +// Parse command line options. +// --------------------------------------------------------------------- + +void +PERL5::parse_args(int argc, char *argv[]) { + + int i = 1; + + export_all = 0; + sprintf(LibDir,"%s", perl_path); + + // Look for certain command line options + + // Get options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if(strcmp(argv[i],"-package") == 0) { + if (argv[i+1]) { + package = new char[strlen(argv[i+1])+1]; + strcpy(package, argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-module") == 0) { + if (argv[i+1]) { + module = new char[strlen(argv[i+1])+1]; + strcpy(module, argv[i+1]); + cmodule = module; + cmodule.replace(":","_"); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-exportall") == 0) { + export_all = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-static") == 0) { + is_static = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-shadow") == 0) { + blessed = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-hide") == 0) { + if (argv[i+1]) { + hide = new char[strlen(argv[i+1])+1]; + strcpy(hide, argv[i+1]); + chide = hide; + chide.replace(":","_"); + hidden = 1; + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-alt-header") == 0) { + if (argv[i+1]) { + alt_header = copy_string(argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-compat") == 0) { + compat = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-help") == 0) { + fputs(usage,stderr); + } + } + } + // Add a symbol for this module + + add_symbol("SWIGPERL",0,0); + add_symbol("SWIGPERL5",0,0); + + // Set name of typemaps + + typemap_lang = "perl5"; + +} + +// ------------------------------------------------------------------ +// PERL5::parse() +// +// Parse an interface file +// ------------------------------------------------------------------ + +void +PERL5::parse() { + + + printf("Generating wrappers for Perl 5\n"); + + // Print out PERL5 specific headers + + headers(); + + // Run the parser + + yyparse(); + fputs(vinit.get(),f_wrappers); +} + + +// --------------------------------------------------------------------- +// PERL5::set_module(char *mod_name, char **mod_list) +// +// Sets the module name. +// Does nothing if it's already set (so it can be overridden as a command +// line option). +// +//---------------------------------------------------------------------- +static String modinit, modextern; + +void PERL5::set_module(char *mod_name, char **mod_list) { + int i; + if (import_file) { + if (!(strcmp(import_file,input_file+strlen(input_file)-strlen(import_file)))) { + if (blessed) { + fprintf(f_pm,"require %s;\n", mod_name); + } + delete [] import_file; + import_file = 0; + } + } + + if (module) return; + + module = new char[strlen(mod_name)+1]; + strcpy(module,mod_name); + + // if there was a mod_list specified, make this big hack + if (mod_list) { + modinit << "#define SWIGMODINIT "; + modextern << "#ifdef __cplusplus\n" + << "extern \"C\" {\n" + << "#endif\n"; + i = 0; + while(mod_list[i]) { + modinit << "newXS(\"" << mod_list[i] << "::boot_" << mod_list[i] << "\", boot_" << mod_list[i] << ", file);\\\n"; + modextern << "extern void boot_" << mod_list[i] << "(CV *);\n"; + i++; + } + modextern << "#ifdef __cplusplus\n" + << "}\n" + << "#endif\n"; + modinit << "/* End of extern module initialization */\n"; + } + + // Create a C module name and put it in 'cmodule' + + cmodule = module; + cmodule.replace(":","_"); +} + +// --------------------------------------------------------------------- +// PERL5::set_init(char *iname) +// +// Sets the initialization function name. +// Does nothing if it's already set +// +//---------------------------------------------------------------------- + +void PERL5::set_init(char *iname) { + set_module(iname,0); +} + +// --------------------------------------------------------------------- +// PERL5::headers(void) +// +// Generate the appropriate header files for PERL5 interface. +// ---------------------------------------------------------------------- + +void PERL5::headers(void) +{ + + emit_banner(f_header); + + if (!alt_header) { + if (insert_file("headers.swg", f_header) == -1) { + fprintf(stderr,"Perl5 : Fatal error. Unable to locate headers.swg. Possible installation problem.\n"); + SWIG_exit(1); + } + } else { + if (insert_file(alt_header, f_header) == -1) { + fprintf(stderr,"SWIG : Fatal error. Unable to locate %s.\n",alt_header); + SWIG_exit(1); + } + } + + if (NoInclude) { + fprintf(f_header,"#define SWIG_NOINCLUDE\n"); + } + + // Get special SWIG related declarations + if (insert_file("perl5.swg", f_header) == -1) { + fprintf(stderr,"SWIG : Fatal error. Unable to locate 'perl5.swg' in SWIG library.\n"); + SWIG_exit(1); + } + + // Get special SWIG related declarations + if (insert_file("perl5mg.swg", f_header) == -1) { + fprintf(stderr,"SWIG : Fatal error. Unable to locate 'perl5mg.swg' in SWIG library.\n"); + SWIG_exit(1); + } + +} + +// -------------------------------------------------------------------- +// PERL5::initialize() +// +// Output initialization code that registers functions with the +// interface. +// --------------------------------------------------------------------- + +void PERL5::initialize() +{ + + char filen[256]; + + if (!module){ + module = "swig"; + fprintf(stderr,"SWIG : *** Warning. No module name specified.\n"); + } + + if (!package) { + package = new char[strlen(module)+1]; + strcpy(package,module); + } + + // If we're in blessed mode, change the package name to "packagec" + + if (blessed) { + char *newpackage = new char[strlen(package)+2]; + sprintf(newpackage,"%sc",package); + realpackage = package; + package = newpackage; + } else { + realpackage = package; + } + + // Create a .pm file + // Need to strip off any prefixes that might be found in + // the module name + + { + char *m = module + strlen(module); + while (m != module) { + if (*m == ':') { + m++; + break; + } + m--; + } + sprintf(filen,"%s%s.pm", output_dir,m); + if ((f_pm = fopen(filen,"w")) == 0) { + fprintf(stderr,"Unable to open %s\n", filen); + SWIG_exit(0); + } + } + if (!blessed) { + smodule = module; + } else if (is_static) { + smodule = new char[strlen(module)+2]; + strcpy(smodule,module); + strcat(smodule,"c"); + cmodule << "c"; + } else { + smodule = module; + } + + // + // Fully qualifies package and realpackage + // + if(hidden) { + char* tmp = new char[strlen(package) + strlen(hide) + 3]; + sprintf(tmp, "%s::%s", hide, realpackage); + delete [] realpackage; + realpackage = tmp; + if(blessed) { + delete [] package; + tmp = new char[strlen(realpackage) + 2]; + sprintf(tmp, "%sc", realpackage); + package = tmp; + } else { + package = realpackage; + } + } + + { + String tmp(realpackage); + tmp.replace(":","_"); + + fprintf(f_header,"#define SWIG_init boot_%s\n\n", tmp.get()); + fprintf(f_header,"#define SWIG_name \"%s::boot_%s\"\n", package, tmp.get()); + } + fprintf(f_header,"#define SWIG_varinit \"%s::var_%s_init();\"\n", package, cmodule.get()); + fprintf(f_header,"#ifdef __cplusplus\n"); + fprintf(f_header,"extern \"C\"\n"); + fprintf(f_header,"#endif\n"); + fprintf(f_header,"#ifndef PERL_OBJECT\n"); + fprintf(f_header,"SWIGEXPORT(void) SWIG_init (CV* cv);\n"); + fprintf(f_header,"#else\n"); + fprintf(f_header,"SWIGEXPORT(void) SWIG_init (CV *cv, CPerlObj *);\n"); + fprintf(f_header,"#endif\n"); + fprintf(f_init,"#ifdef __cplusplus\n"); + fprintf(f_init,"extern \"C\"\n"); + fprintf(f_init,"#endif\n"); + fprintf(f_init,"XS(SWIG_init) {\n"); + fprintf(f_init,"\t dXSARGS;\n"); + fprintf(f_init,"\t char *file = __FILE__;\n"); + fprintf(f_init,"\t cv = cv; items = items;\n"); + fprintf(f_init,"\t newXS(\"%s::var_%s_init\", _wrap_perl5_%s_var_init, file);\n",package,cmodule.get(), cmodule.get()); + vinit << "XS(_wrap_perl5_" << cmodule << "_var_init) {\n" + << tab4 << "dXSARGS;\n" + << tab4 << "SV *sv;\n" + << tab4 << "cv = cv; items = items;\n"; + + fprintf(f_pm,"# This file was automatically generated by SWIG\n"); + fprintf(f_pm,"package %s;\n",realpackage); + fprintf(f_pm,"require Exporter;\n"); + if (!is_static) { + fprintf(f_pm,"require DynaLoader;\n"); + fprintf(f_pm,"@ISA = qw(Exporter DynaLoader);\n"); + } else { + fprintf(f_pm,"@ISA = qw(Exporter);\n"); + } + + // Start creating magic code + + + magic << "#ifdef PERL_OBJECT\n" + << "#define MAGIC_CLASS _wrap_" << module << "_var::\n" + << "class _wrap_" << module << "_var : public CPerlObj {\n" + << "public:\n" + << "#else\n" + << "#define MAGIC_CLASS\n" + << "#endif\n" + << "SWIGCLASS_STATIC int swig_magic_readonly(SV *sv, MAGIC *mg) {\n" + << tab4 << "MAGIC_PPERL\n" + << tab4 << "sv = sv; mg = mg;\n" + << tab4 << "croak(\"Value is read-only.\");\n" + << tab4 << "return 0;\n" + << "}\n"; // Dump out external module declarations + + /* Process additional initialization files here */ + + if (strlen(modinit.get()) > 0) { + fprintf(f_header,"%s\n",modinit.get()); + } + if (strlen(modextern.get()) > 0) { + fprintf(f_header,"%s\n",modextern.get()); + } +} + +// --------------------------------------------------------------------- +// PERL5::import(char *filename) +// +// Import directive +// --------------------------------------------------------------------- + +void PERL5::import(char *filename) { + if (import_file) delete [] import_file; + import_file = copy_string(filename); +} + + +// --------------------------------------------------------------------- +// PERL5::close(void) +// +// Wrap things up. Close initialization function. +// --------------------------------------------------------------------- + +void PERL5::close(void) +{ + String base; + + // Dump out variable wrappers + + magic << "\n\n#ifdef PERL_OBJECT\n" + << "};\n" + << "#endif\n"; + + fprintf(f_header,"%s\n", magic.get()); + + emit_ptr_equivalence(f_init); + + fprintf(f_init,"\t ST(0) = &PL_sv_yes;\n"); + fprintf(f_init,"\t XSRETURN(1);\n"); + fprintf(f_init,"}\n"); + + vinit << tab4 << "XSRETURN(1);\n" + << "}\n"; + + fprintf(f_pm,"package %s;\n", package); + + if (!is_static) { + fprintf(f_pm,"bootstrap %s;\n", realpackage); + } else { + String tmp(realpackage); + tmp.replace(":","_"); + fprintf(f_pm,"boot_%s();\n", tmp); + } + fprintf(f_pm,"var_%s_init();\n", cmodule.get()); + fprintf(f_pm,"%s",pragma_include.get()); + fprintf(f_pm,"package %s;\n", realpackage); + fprintf(f_pm,"@EXPORT = qw(%s );\n",exported.get()); + + if (blessed) { + + base << "\n# ---------- BASE METHODS -------------\n\n" + << "package " << realpackage << ";\n\n"; + + // Write out the TIE method + + base << "sub TIEHASH {\n" + << tab4 << "my ($classname,$obj) = @_;\n" + << tab4 << "return bless $obj, $classname;\n" + << "}\n\n"; + + // Output a CLEAR method. This is just a place-holder, but by providing it we + // can make declarations such as + // %$u = ( x => 2, y=>3, z =>4 ); + // + // Where x,y,z are the members of some C/C++ object. + + base << "sub CLEAR { }\n\n"; + + // Output default firstkey/nextkey methods + + base << "sub FIRSTKEY { }\n\n"; + base << "sub NEXTKEY { }\n\n"; + + // Output a 'this' method + + base << "sub this {\n" + << tab4 << "my $ptr = shift;\n" + << tab4 << "return tied(%$ptr);\n" + << "}\n\n"; + + fprintf(f_pm,"%s",base.get()); + + // Emit function stubs for stand-alone functions + + fprintf(f_pm,"\n# ------- FUNCTION WRAPPERS --------\n\n"); + fprintf(f_pm,"package %s;\n\n",realpackage); + fprintf(f_pm,"%s",func_stubs.get()); + + + // Emit package code for different classes + + fprintf(f_pm,"%s",pm.get()); + + // Emit variable stubs + + fprintf(f_pm,"\n# ------- VARIABLE STUBS --------\n\n"); + fprintf(f_pm,"package %s;\n\n",realpackage); + fprintf(f_pm,"%s",var_stubs.get()); + + } + + fprintf(f_pm,"1;\n"); + fclose(f_pm); + + // Patch up documentation title + + if ((doc_entry) && (module)) { + doc_entry->cinfo << "Module : " << module << ", " + << "Package : " << realpackage; + } + +} + +// ---------------------------------------------------------------------- +// char *PERL5::type_mangle(DataType *t) +// +// Mangles a datatype into a Perl5 name compatible with xsubpp type +// T_PTROBJ. +// ---------------------------------------------------------------------- + +char * +PERL5::type_mangle(DataType *t) { + static char result[128]; + int i; + char *r, *c; + + if (blessed) { + + // Check to see if we've blessed this datatype + + if ((classes.lookup(t->name)) && (t->is_pointer <= 1)) { + + // This is a blessed class. Return just the type-name + strcpy(result,(char *) classes.lookup(t->name)); + return result; + } + } + + r = result; + c = t->name; + + for ( c = t->name; *c; c++,r++) { + *r = *c; + } + for (i = 0; i < (t->is_pointer-t->implicit_ptr); i++, r++) { + strcpy(r,"Ptr"); + r+=2; + } + *r = 0; + return result; +} + +// ---------------------------------------------------------------------- +// PERL5::get_pointer(char *iname, char *srcname, char *src, char *target, +// DataType *t, String &f, char *ret) +// +// Emits code to get a pointer from a parameter and do type checking. +// ---------------------------------------------------------------------- + +void PERL5::get_pointer(char *iname, char *srcname, char *src, char *dest, + DataType *t, String &f, char *ret) { + + // Now get the pointer value from the string and save in dest + + f << tab4 << "if (SWIG_GetPtr(" << src << ",(void **) &" << dest << ","; + + // If we're passing a void pointer, we give the pointer conversion a NULL + // pointer, otherwise pass in the expected type. + + if (t->type == T_VOID) f << "(char *) 0 )) {\n"; + else + f << "\"" << (hidden ? realpackage : "") << (hidden ? "::" : "") << t->print_mangle() << "\")) {\n"; + + // This part handles the type checking according to three different + // levels. 0 = no checking, 1 = warning message, 2 = strict. + + switch(TypeStrict) { + case 0: // No type checking + f << tab4 << "}\n"; + break; + + case 1: // Warning message only + + // Change this part to how you want to handle a type-mismatch warning. + // By default, it will just print to stderr. + + f << tab8 << "fprintf(stderr,\"Warning : type mismatch in " << srcname + << " of " << iname << ". Expected " << (hidden ? realpackage : "") << (hidden ? "::" : "") << t->print_mangle() + << ", received %s\\n\"," << src << ");\n" + << tab4 << "}\n"; + + break; + case 2: // Super strict mode. + + // Change this part to return an error. + + f << tab8 << "croak(\"Type error in " << srcname + << " of " << iname << ". Expected " << (hidden ? realpackage : "") << (hidden ? "::" : "") << t->print_mangle() << ".\");\n" + << tab8 << ret << ";\n" + << tab4 << "}\n"; + + break; + + default : + fprintf(stderr,"SWIG Error. Unknown strictness level\n"); + break; + } +} + +// ---------------------------------------------------------------------- +// PERL5::create_command(char *cname, char *iname) +// +// Create a command and register it with the interpreter +// ---------------------------------------------------------------------- + +void PERL5::create_command(char *cname, char *iname) { + fprintf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package, iname, name_wrapper(cname,"")); + if (export_all) { + exported << iname << " "; + } +} + +// ---------------------------------------------------------------------- +// PERL5::create_function(char *name, char *iname, DataType *d, +// ParmList *l) +// +// Create a function declaration and register it with the interpreter. +// ---------------------------------------------------------------------- + +void PERL5::create_function(char *name, char *iname, DataType *d, ParmList *l) +{ + Parm *p; + int pcount,i,j; + char *wname; + char *usage = 0; + WrapperFunction f; + char source[256],target[256],temp[256], argnum[32]; + char *tm; + String cleanup,outarg,build; + int numopt = 0; + int need_save, num_saved = 0; // Number of saved arguments. + int have_build = 0; + + // Make a wrapper name for this + + wname = name_wrapper(iname,""); + + // Now write the wrapper function itself....this is pretty ugly + + f.def << "XS(" << wname << ") {\n"; + f.code << tab4 << "cv = cv;\n"; + + pcount = emit_args(d, l, f); + numopt = l->numopt(); + + f.add_local("int","argvi = 0"); + + // Check the number of arguments + + usage = usage_func(iname,d,l); + f.code << tab4 << "if ((items < " << (pcount-numopt) << ") || (items > " << l->numarg() << ")) \n" + << tab8 << "croak(\"Usage: " << usage << "\");\n"; + + // Write code to extract parameters. + // This section should be able to extract virtually any kind + // parameter, represented as a string + + i = 0; + j = 0; + p = l->get_first(); + while (p != 0) { + // Produce string representation of source and target arguments + sprintf(source,"ST(%d)",j); + sprintf(target,"_arg%d",i); + sprintf(argnum,"%d",j+1); + + // Check to see if this argument is being ignored + + if (!p->ignore) { + + // If there are optional arguments, check for this + + if (j>= (pcount-numopt)) + f.code << tab4 << "if (items > " << j << ") {\n"; + + // See if there is a type-map + if ((tm = typemap_lookup("in","perl5",p->t,p->name,source,target,&f))) { + f.code << tm << "\n"; + f.code.replace("$argnum",argnum); + f.code.replace("$arg",source); + } else { + + if (!p->t->is_pointer) { + + // Extract a parameter by "value" + + switch(p->t->type) { + + // Integers + + case T_BOOL: + case T_INT : + case T_SHORT : + case T_LONG : + case T_SINT : + case T_SSHORT: + case T_SLONG: + case T_SCHAR: + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + f.code << tab4 << "_arg" << i << " = " << p->t->print_cast() + << "SvIV(ST(" << j << "));\n"; + break; + case T_CHAR : + + + + f.code << tab4 << "_arg" << i << " = (char) *SvPV(ST(" << j << "),PL_na);\n"; + break; + + // Doubles + + case T_DOUBLE : + case T_FLOAT : + f.code << tab4 << "_arg" << i << " = " << p->t->print_cast() + << " SvNV(ST(" << j << "));\n"; + break; + + // Void.. Do nothing. + + case T_VOID : + break; + + // User defined. This is invalid here. Note, user-defined types by + // value are handled in the parser. + + case T_USER: + + // Unsupported data type + + default : + fprintf(stderr,"%s : Line %d. Unable to use type %s as a function argument.\n",input_file, line_number, p->t->print_type()); + break; + } + } else { + + // Argument is a pointer type. Special case is for char * + // since that is usually a string. + + if ((p->t->type == T_CHAR) && (p->t->is_pointer == 1)) { + f.code << tab4 << "if (! SvOK((SV*) ST(" << j << "))) { " + << "_arg" << i << " = 0; }\n"; + f.code << tab4 << "else { _arg" + << i << " = (char *) SvPV(ST(" << j << "),PL_na); }\n"; + } else { + + // Have a generic pointer type here. Read it in as a swig + // typed pointer. + + sprintf(temp,"argument %d", i+1); + get_pointer(iname,temp,source,target, p->t, f.code, "XSRETURN(1)"); + } + } + } + // The source is going to be an array of saved values. + + sprintf(temp,"_saved[%d]",num_saved); + if (j>= (pcount-numopt)) + f.code << tab4 << "} \n"; + j++; + } else { + temp[0] = 0; + } + // Check to see if there is any sort of "build" typemap (highly complicated) + + if ((tm = typemap_lookup("build","perl5",p->t,p->name,source,target))) { + build << tm << "\n"; + have_build = 1; + } + + // Check if there is any constraint code + if ((tm = typemap_lookup("check","perl5",p->t,p->name,source,target))) { + f.code << tm << "\n"; + f.code.replace("$argnum",argnum); + } + need_save = 0; + + if ((tm = typemap_lookup("freearg","perl5",p->t,p->name,target,temp))) { + cleanup << tm << "\n"; + cleanup.replace("$argnum",argnum); + cleanup.replace("$arg",temp); + need_save = 1; + } + if ((tm = typemap_lookup("argout","perl5",p->t,p->name,target,"ST(argvi)"))) { + String tempstr; + tempstr = tm; + tempstr.replace("$argnum",argnum); + tempstr.replace("$arg",temp); + outarg << tempstr << "\n"; + need_save = 1; + } + // If we needed a saved variable, we need to emit to emit some code for that + // This only applies if the argument actually existed (not ignore) + if ((need_save) && (!p->ignore)) { + f.code << tab4 << temp << " = " << source << ";\n"; + num_saved++; + } + p = l->get_next(); + i++; + } + + // If there were any saved arguments, emit a local variable for them + + if (num_saved) { + sprintf(temp,"_saved[%d]",num_saved); + f.add_local("SV *",temp); + } + + // If there was a "build" typemap, we need to go in and perform a serious hack + + if (have_build) { + char temp1[32]; + char temp2[256]; + l->sub_parmnames(build); // Replace all parameter names + j = 1; + for (i = 0; i < l->nparms; i++) { + p = l->get(i); + if (strlen(p->name) > 0) { + sprintf(temp1,"_in_%s", p->name); + } else { + sprintf(temp1,"_in_arg%d", i); + } + sprintf(temp2,"argv[%d]",j); + build.replaceid(temp1,temp2); + if (!p->ignore) + j++; + } + f.code << build; + } + + // Now write code to make the function call + + emit_func_call(name,d,l,f); + + // See if there was a typemap + if ((tm = typemap_lookup("out","perl5",d,iname,"_result","ST(argvi)"))) { + // Yep. Use it instead of the default + f.code << tm << "\n"; + } else if ((d->type != T_VOID) || (d->is_pointer)) { + if (!d->is_pointer) { + + // Function returns a "value" + f.code << tab4 << "ST(argvi) = sv_newmortal();\n"; + switch(d->type) { + case T_INT: case T_BOOL: case T_SINT: case T_UINT: + case T_SHORT: case T_SSHORT: case T_USHORT: + case T_LONG : case T_SLONG : case T_ULONG: + case T_SCHAR: case T_UCHAR : + f.code << tab4 << "sv_setiv(ST(argvi++),(IV) _result);\n"; + break; + case T_DOUBLE : + case T_FLOAT : + f.code << tab4 << "sv_setnv(ST(argvi++), (double) _result);\n"; + break; + case T_CHAR : + f.add_local("char", "_ctemp[2]"); + f.code << tab4 << "_ctemp[0] = _result;\n" + << tab4 << "_ctemp[1] = 0;\n" + << tab4 << "sv_setpv((SV*)ST(argvi++),_ctemp);\n"; + break; + + // Return a complex type by value + + case T_USER: + d->is_pointer++; + f.code << tab4 << "sv_setref_pv(ST(argvi++),\"" << (hidden ? realpackage : "") << (hidden ? "::" : "") << d->print_mangle() + << "\", (void *) _result);\n"; + d->is_pointer--; + break; + + default : + fprintf(stderr,"%s: Line %d. Unable to use return type %s in function %s.\n", input_file, line_number, d->print_type(), name); + break; + } + } else { + + // Is a pointer return type + f.code << tab4 << "ST(argvi) = sv_newmortal();\n"; + if ((d->type == T_CHAR) && (d->is_pointer == 1)) { + + // Return a character string + f.code << tab4 << "sv_setpv((SV*)ST(argvi++),(char *) _result);\n"; + + } else { + // Is an ordinary pointer type. + f.code << tab4 << "sv_setref_pv(ST(argvi++),\"" << (hidden ? realpackage : "") << (hidden ? "::" : "") << d->print_mangle() + << "\", (void *) _result);\n"; + } + } + } + + // If there were any output args, take care of them. + + f.code << outarg; + + // If there was any cleanup, do that. + + f.code << cleanup; + + if (NewObject) { + if ((tm = typemap_lookup("newfree","perl5",d,iname,"_result",""))) { + f.code << tm << "\n"; + } + } + + if ((tm = typemap_lookup("ret","perl5",d,iname,"_result",""))) { + // Yep. Use it instead of the default + f.code << tm << "\n"; + } + + // Wrap things up (in a manner of speaking) + + f.code << tab4 << "XSRETURN(argvi);\n}\n"; + + // Add the dXSARGS last + + f.add_local("dXSARGS",""); + + // Substitute the cleanup code + f.code.replace("$cleanup",cleanup); + f.code.replace("$name",iname); + + // Dump this function out + + f.print(f_wrappers); + + // Create a first crack at a documentation entry + + if (doc_entry) { + static DocEntry *last_doc_entry = 0; + doc_entry->usage << usage; + if (last_doc_entry != doc_entry) { + doc_entry->cinfo << "returns " << d->print_type(); + last_doc_entry = doc_entry; + } + } + + // Now register the function + + fprintf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package, iname, wname); + + if (export_all) { + exported << iname << " "; + } + + + // -------------------------------------------------------------------- + // Create a stub for this function, provided it's not a member function + // + // Really we only need to create a stub if this function involves + // complex datatypes. If it does, we'll make a small wrapper to + // process the arguments. If it doesn't, we'll just make a symbol + // table entry. + // -------------------------------------------------------------------- + + if ((blessed) && (!member_func)) { + int need_stub = 0; + String func; + + // We'll make a stub since we may need it anyways + + func << "sub " << iname << " {\n" + << tab4 << "my @args = @_;\n"; + + + // Now we have to go through and patch up the argument list. If any + // arguments to our function correspond to other Perl objects, we + // need to extract them from a tied-hash table object. + + Parm *p = l->get_first(); + int i = 0; + while(p) { + + if (!p->ignore) { + // Look up the datatype name here + String sourceNtarget; + sourceNtarget << "$args[" << i << "]"; + + if ((tm = typemap_lookup("perl5in","perl5",p->t,"",sourceNtarget,sourceNtarget))) + func << tm << "\n"; + else if ((classes.lookup(p->t->name)) && (p->t->is_pointer <= 1)) { + if (i >= (pcount - numopt)) + func << tab4 << "if (scalar(@args) >= " << i << ") {\n" << tab4; + + func << tab4 << "$args[" << i << "] = tied(%{$args[" << i << "]});\n"; + + if (i >= (pcount - numopt)) + func << tab4 << "}\n"; + + need_stub = 1; + } + i++; + } + p = l->get_next(); + } + + func << tab4 << "my $result = " << package << "::" << iname << "(@args);\n"; + + // Now check to see what kind of return result was found. + // If this function is returning a result by 'value', SWIG did an + // implicit malloc/new. We'll mark the object like it was created + // in Perl so we can garbage collect it. + + if ((tm = typemap_lookup("perl5out","perl5",d,"",name,"sv"))) { + func << tm << "\n" + << tab4 <<"return $result;\n" + << "}\n"; + } else if ((classes.lookup(d->name)) && (d->is_pointer <=1)) { + + func << tab4 << "return undef if (!defined($result));\n"; + + // If we're returning an object by value, put it's reference + // into our local hash table + + if ((d->is_pointer == 0) || ((d->is_pointer == 1) && NewObject)) { + func << tab4 << "$" << (char *) classes.lookup(d->name) << "::OWNER{$result} = 1;\n"; + } + + // We're returning a Perl "object" of some kind. Turn it into + // a tied hash + + func << tab4 << "my %resulthash;\n" + /* << tab4 << "tie %resulthash, \"" << (char *) classes.lookup(d->name) << "\", $result;\n" + << tab4 << "return bless \\%resulthash, \"" << (char *) classes.lookup(d->name) << "\";\n" + */ + << tab4 << "tie %resulthash, ref($result), $result;\n" + << tab4 << "return bless \\%resulthash, ref($result);\n" + << "}\n"; + + need_stub = 1; + } else { + + // Hmmm. This doesn't appear to be anything I know about so just + // return it unmolested. + + func << tab4 <<"return $result;\n" + << "}\n"; + + } + + // Now check if we needed the stub. If so, emit it, otherwise + // Emit code to hack Perl's symbol table instead + + if (need_stub) { + func_stubs << func; + } else { + func_stubs << "*" << iname << " = *" << package << "::" << iname << ";\n"; + } + } +} + +// ----------------------------------------------------------------------- +// PERL5::link_variable(char *name, char *iname, DataType *d) +// +// Create a link to a C variable. +// ----------------------------------------------------------------------- + +void PERL5::link_variable(char *name, char *iname, DataType *t) +{ + char set_name[256]; + char val_name[256]; + WrapperFunction getf, setf; + char *tm; + sprintf(set_name,"_wrap_set_%s",iname); + sprintf(val_name,"_wrap_val_%s",iname); + + // Create a new scalar that we will attach magic to + + vinit << tab4 << "sv = perl_get_sv(\"" << package << "::" << iname << "\",TRUE | 0x2);\n"; + + // Create a Perl function for setting the variable value + + if (!(Status & STAT_READONLY)) { + setf.def << "SWIGCLASS_STATIC int " << set_name << "(SV* sv, MAGIC *mg) {\n"; + + setf.code << tab4 << "MAGIC_PPERL\n"; + setf.code << tab4 << "mg = mg;\n"; + + /* Check for a few typemaps */ + if ((tm = typemap_lookup("varin","perl5",t,"","sv",name))) { + setf.code << tm << "\n"; + } else if ((tm = typemap_lookup("in","perl5",t,"","sv",name))) { + setf.code << tm << "\n"; + } else { + if (!t->is_pointer) { + + // Set the value to something + + switch(t->type) { + case T_INT : case T_BOOL: case T_SINT : case T_UINT: + case T_SHORT : case T_SSHORT : case T_USHORT: + case T_LONG : case T_SLONG : case T_ULONG: + case T_UCHAR: case T_SCHAR: + setf.code << tab4 << name << " = " << t->print_cast() << " SvIV(sv);\n"; + break; + case T_DOUBLE : + case T_FLOAT : + setf.code << tab4 << name << " = " << t->print_cast() << " SvNV(sv);\n"; + break; + case T_CHAR : + setf.code << tab4 << name << " = (char) *SvPV(sv,PL_na);\n"; + break; + + case T_USER: + + // Add support for User defined type here + // Get as a pointer value + + t->is_pointer++; + setf.add_local("void","*_temp"); + get_pointer(iname,"value","sv","_temp", t, setf.code, "return(1)"); + setf.code << tab4 << name << " = *(" << t->print_cast() << " _temp);\n"; + t->is_pointer--; + break; + + default : + fprintf(stderr,"%s : Line %d. Unable to link with datatype %s (ignored).\n", input_file, line_number, t->print_type()); + return; + } + } else { + // Have some sort of pointer type here, Process it differently + if ((t->type == T_CHAR) && (t->is_pointer == 1)) { + setf.add_local("char","*_a"); + setf.code << tab4 << "_a = (char *) SvPV(sv,PL_na);\n"; + + if (CPlusPlus) + setf.code << tab4 << "if (" << name << ") delete [] " << name << ";\n" + << tab4 << name << " = new char[strlen(_a)+1];\n"; + else + setf.code << tab4 << "if (" << name << ") free(" << name << ");\n" + << tab4 << name << " = (char *) malloc(strlen(_a)+1);\n"; + setf.code << "strcpy(" << name << ",_a);\n"; + } else { + // Set the value of a pointer + + setf.add_local("void","*_temp"); + get_pointer(iname,"value","sv","_temp", t, setf.code, "return(1)"); + setf.code << tab4 << name << " = " << t->print_cast() << " _temp;\n"; + } + } + } + setf.code << tab4 << "return 1;\n" + << "}\n"; + + setf.code.replace("$name",iname); + setf.print(magic); + + } + + // Now write a function to evaluate the variable + + getf.def << "SWIGCLASS_STATIC int " << val_name << "(SV *sv, MAGIC *mg) {\n"; + getf.code << tab4 << "MAGIC_PPERL\n"; + getf.code << tab4 << "mg = mg;\n"; + + // Check for a typemap + + if ((tm = typemap_lookup("varout","perl5",t,"",name, "sv"))) { + getf.code << tm << "\n"; + } else if ((tm = typemap_lookup("out","perl5",t,"",name,"sv"))) { + setf.code << tm << "\n"; + } else { + if (!t->is_pointer) { + switch(t->type) { + case T_INT : case T_BOOL: case T_SINT: case T_UINT: + case T_SHORT : case T_SSHORT: case T_USHORT: + case T_LONG : case T_SLONG : case T_ULONG: + case T_UCHAR: case T_SCHAR: + getf.code << tab4 << "sv_setiv(sv, (IV) " << name << ");\n"; + vinit << tab4 << "sv_setiv(sv,(IV)" << name << ");\n"; + break; + case T_DOUBLE : + case T_FLOAT : + getf.code << tab4 << "sv_setnv(sv, (double) " << name << ");\n"; + vinit << tab4 << "sv_setnv(sv,(double)" << name << ");\n"; + break; + case T_CHAR : + getf.add_local("char","_ptemp[2]"); + getf.code << tab4 << "_ptemp[0] = " << name << ";\n" + << tab4 << "_ptemp[1] = 0;\n" + << tab4 << "sv_setpv((SV*) sv, _ptemp);\n"; + break; + case T_USER: + t->is_pointer++; + getf.code << tab4 << "rsv = SvRV(sv);\n" + << tab4 << "sv_setiv(rsv,(IV) &" << name << ");\n"; + + // getf.code << tab4 << "sv_setref_pv((SV*) sv,\"" << t->print_mangle() + // << "\", (void *) &" << name << ");\n"; + + getf.add_local("SV","*rsv"); + vinit << tab4 << "sv_setref_pv(sv,\"" << t->print_mangle() << "\",(void *) &" << name << ");\n"; + t->is_pointer--; + + break; + default : + break; + } + } else { + + // Have some sort of arbitrary pointer type. Return it as a string + + if ((t->type == T_CHAR) && (t->is_pointer == 1)) + getf.code << tab4 << "sv_setpv((SV*) sv, " << name << ");\n"; + else { + getf.code << tab4 << "rsv = SvRV(sv);\n" + << tab4 << "sv_setiv(rsv,(IV) " << name << ");\n"; + getf.add_local("SV","*rsv"); + vinit << tab4 << "sv_setref_pv(sv,\"" << t->print_mangle() << "\",(void *) 1);\n"; + + //getf.code << tab4 << "sv_setref_pv((SV*) sv,\"" << t->print_mangle() + // << "\", (void *) " << name << ");\n"; + } + } + } + getf.code << tab4 << "return 1;\n" + << "}\n"; + + getf.code.replace("$name",iname); + getf.print(magic); + + // Now add symbol to the PERL interpreter + if (Status & STAT_READONLY) { + vinit << tab4 << "swig_create_magic(sv,\"" << package << "::" << iname << "\",MAGIC_CAST MAGIC_CLASS swig_magic_readonly, MAGIC_CAST MAGIC_CLASS " << val_name << ");\n"; + } else { + vinit << tab4 << "swig_create_magic(sv,\"" << package << "::" << iname << "\", MAGIC_CAST MAGIC_CLASS " << set_name << ", MAGIC_CAST MAGIC_CLASS " << val_name << ");\n"; + } + // Add a documentation entry + + if (doc_entry) { + doc_entry->usage << usage_var(iname,t); + doc_entry->cinfo << "Global : " << t->print_type() << " " << name; + } + + // If we're blessed, try to figure out what to do with the variable + // 1. If it's a Perl object of some sort, create a tied-hash + // around it. + // 2. Otherwise, just hack Perl's symbol table + + if (blessed) { + if ((classes.lookup(t->name)) && (t->is_pointer <= 1)) { + var_stubs << "\nmy %__" << iname << "_hash;\n" + << "tie %__" << iname << "_hash,\"" << (char *) classes.lookup(t->name) << "\", $" + << package << "::" << iname << ";\n" + << "$" << iname << "= \\%__" << iname << "_hash;\n" + << "bless $" << iname << ", " << (char *) classes.lookup(t->name) << ";\n"; + } else { + var_stubs << "*" << iname << " = *" << package << "::" << iname << ";\n"; + } + if (export_all) + exported << "$" << name << " "; + } +} + +// ----------------------------------------------------------------------- +// PERL5::declare_const(char *name, char *iname, DataType *type, char *value) +// +// Makes a constant. Really just creates a variable and creates a read-only +// link to it. +// ------------------------------------------------------------------------ + +// Functions used to create constants + +static const char *setiv = "#ifndef PERL_OBJECT\ +\n#define swig_setiv(a,b) _swig_setiv(a,b)\ +\nstatic void _swig_setiv(char *name, long value) { \ +\n#else\ +\n#define swig_setiv(a,b) _swig_setiv(pPerl,a,b)\ +\nstatic void _swig_setiv(CPerlObj *pPerl, char *name, long value) { \ +\n#endif\ +\n SV *sv; \ +\n sv = perl_get_sv(name,TRUE | 0x2);\ +\n sv_setiv(sv, (IV) value);\ +\n SvREADONLY_on(sv);\ +\n}\n"; + +static const char *setnv = "#ifndef PERL_OBJECT\ +\n#define swig_setnv(a,b) _swig_setnv(a,b)\ +\nstatic void _swig_setnv(char *name, double value) { \ +\n#else\ +\n#define swig_setnv(a,b) _swig_setnv(pPerl,a,b)\ +\nstatic void _swig_setnv(CPerlObj *pPerl, char *name, double value) { \ +\n#endif\ +\n SV *sv; \ +\n sv = perl_get_sv(name,TRUE | 0x2);\ +\n sv_setnv(sv, value);\ +\n SvREADONLY_on(sv);\ +\n}\n"; + +static const char *setpv = "#ifndef PERL_OBJECT\ +\n#define swig_setpv(a,b) _swig_setpv(a,b)\ +\nstatic void _swig_setpv(char *name, char *value) { \ +\n#else\ +\n#define swig_setpv(a,b) _swig_setpv(pPerl,a,b)\ +\nstatic void _swig_setpv(CPerlObj *pPerl, char *name, char *value) { \ +\n#endif\ +\n SV *sv; \ +\n sv = perl_get_sv(name,TRUE | 0x2);\ +\n sv_setpv(sv, value);\ +\n SvREADONLY_on(sv);\ +\n}\n"; + +static const char *setrv = "#ifndef PERL_OBJECT\ +\n#define swig_setrv(a,b,c) _swig_setrv(a,b,c)\ +\nstatic void _swig_setrv(char *name, void *value, char *type) { \ +\n#else\ +\n#define swig_setrv(a,b,c) _swig_setrv(pPerl,a,b,c)\ +\nstatic void _swig_setrv(CPerlObj *pPerl, char *name, void *value, char *type) { \ +\n#endif\ +\n SV *sv; \ +\n sv = perl_get_sv(name,TRUE | 0x2);\ +\n sv_setref_pv(sv, type, value);\ +\n SvREADONLY_on(sv);\ +\n}\n"; + +void +PERL5::declare_const(char *name, char *, DataType *type, char *value) + { + + char *tm; + static int have_int_func = 0; + static int have_double_func = 0; + static int have_char_func = 0; + static int have_ref_func = 0; + + if ((tm = typemap_lookup("const","perl5",type,name,value,name))) { + fprintf(f_init,"%s\n",tm); + } else { + if ((type->type == T_USER) && (!type->is_pointer)) { + fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number); + return; + } + // Generate a constant + // vinit << tab4 << "sv = perl_get_sv(\"" << package << "::" << name << "\",TRUE);\n"; + if (type->is_pointer == 0) { + switch(type->type) { + case T_INT:case T_SINT: case T_UINT: case T_BOOL: + case T_SHORT: case T_SSHORT: case T_USHORT: + case T_LONG: case T_SLONG: case T_ULONG: + case T_SCHAR: case T_UCHAR: + if (!have_int_func) { + fprintf(f_header,"%s\n",setiv); + have_int_func = 1; + } + vinit << tab4 << "swig_setiv(\"" << package << "::" << name << "\", (long) " << value << ");\n"; + break; + case T_DOUBLE: + case T_FLOAT: + if (!have_double_func) { + fprintf(f_header,"%s\n",setnv); + have_double_func = 1; + } + vinit << tab4 << "swig_setnv(\"" << package << "::" << name << "\", (double) (" << value << "));\n"; + break; + case T_CHAR : + if (!have_char_func) { + fprintf(f_header,"%s\n",setpv); + have_char_func = 1; + } + vinit << tab4 << "swig_setpv(\"" << package << "::" << name << "\", \"" << value << "\");\n"; + break; + default: + fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number); + break; + } + } else { + if ((type->type == T_CHAR) && (type->is_pointer == 1)) { + if (!have_char_func) { + fprintf(f_header,"%s\n",setpv); + have_char_func = 1; + } + vinit << tab4 << "swig_setpv(\"" << package << "::" << name << "\", \"" << value << "\");\n"; + } else { + // A user-defined type. We're going to munge it into a string pointer value + if (!have_ref_func) { + fprintf(f_header,"%s\n",setrv); + have_ref_func = 1; + } + vinit << tab4 << "swig_setrv(\"" << package << "::" << name << "\", (void *) " << value << ", \"" + << type->print_mangle() << "\");\n"; + } + } + } + + // Patch up the documentation entry + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << usage_const(name,type,value); + doc_entry->cinfo = ""; + doc_entry->cinfo << "Constant: " << type->print_type(); + } + + if (blessed) { + if ((classes.lookup(type->name)) && (type->is_pointer <= 1)) { + var_stubs << "\nmy %__" << name << "_hash;\n" + << "tie %__" << name << "_hash,\"" << (char *) classes.lookup(type->name) << "\", $" + << package << "::" << name << ";\n" + << "$" << name << "= \\%__" << name << "_hash;\n" + << "bless $" << name << ", " << (char *) classes.lookup(type->name) << ";\n"; + } else { + var_stubs << "*" << name << " = *" << package << "::" << name << ";\n"; + } + } + if (export_all) + exported << "$" << name << " "; +} + +// ---------------------------------------------------------------------- +// PERL5::usage_var(char *iname, DataType *t) +// +// Produces a usage string for a Perl 5 variable. +// ---------------------------------------------------------------------- + +char *PERL5::usage_var(char *iname, DataType *) { + + static char temp[1024]; + char *c; + + sprintf(temp,"$%s", iname); + c = temp + strlen(temp); + return temp; +} + +// --------------------------------------------------------------------------- +// char *PERL5::usage_func(pkg, char *iname, DataType *t, ParmList *l) +// +// Produces a usage string for a function in Perl +// --------------------------------------------------------------------------- + +char *PERL5::usage_func(char *iname, DataType *, ParmList *l) { + + static String temp; + Parm *p; + int i; + + temp = ""; + temp << iname << "("; + + /* Now go through and print parameters */ + + p = l->get_first(); + i = 0; + while (p != 0) { + if (!p->ignore) { + /* If parameter has been named, use that. Otherwise, just print a type */ + + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + if (strlen(p->name) > 0) { + temp << p->name; + } else { + temp << p->t->print_type(); + } + } + i++; + p = l->get_next(); + if (p) + if (!p->ignore) + temp << ","; + } else { + p = l->get_next(); + if (p) + if ((i>0) && (!p->ignore)) + temp << ","; + } + } + temp << ");"; + return temp.get(); +} + +// ---------------------------------------------------------------------- +// PERL5::usage_const(char *iname, DataType *type, char *value) +// +// Produces a usage string for a Perl 5 constant +// ---------------------------------------------------------------------- + +char *PERL5::usage_const(char *iname, DataType *, char *value) { + + static char temp[1024]; + if (value) { + sprintf(temp,"$%s = %s", iname, value); + } else { + sprintf(temp,"$%s", iname); + } + return temp; +} + +// ----------------------------------------------------------------------- +// PERL5::add_native(char *name, char *funcname) +// +// Add a native module name to Perl5. +// ----------------------------------------------------------------------- + +void PERL5::add_native(char *name, char *funcname) { + fprintf(f_init,"\t newXS(\"%s::%s\", %s, file);\n", package,name, funcname); + if (export_all) + exported << name << " "; + if (blessed) { + func_stubs << "*" << name << " = *" << package << "::" << name << ";\n"; + } +} + +/**************************************************************************** + *** OBJECT-ORIENTED FEATURES + **************************************************************************** + *** These extensions provide a more object-oriented interface to C++ + *** classes and structures. The code here is based on extensions + *** provided by David Fletcher and Gary Holt. + *** + *** I have generalized these extensions to make them more general purpose + *** and to resolve object-ownership problems. + *** + *** The approach here is very similar to the Python module : + *** 1. All of the original methods are placed into a single + *** package like before except that a 'c' is appended to the + *** package name. + *** + *** 2. All methods and function calls are wrapped with a new + *** perl function. While possibly inefficient this allows + *** us to catch complex function arguments (which are hard to + *** track otherwise). + *** + *** 3. Classes are represented as tied-hashes in a manner similar + *** to Gary Holt's extension. This allows us to access + *** member data. + *** + *** 4. Stand-alone (global) C functions are modified to take + *** tied hashes as arguments for complex datatypes (if + *** appropriate). + *** + *** 5. Global variables involving a class/struct is encapsulated + *** in a tied hash. + *** + *** 6. Object ownership is maintained by having a hash table + *** within in each package called "this". It is unlikely + *** that C++ program will use this so it's a somewhat + *** safe variable name. + *** + ****************************************************************************/ + +static int class_renamed = 0; +static String fullclassname; + +// -------------------------------------------------------------------------- +// PERL5::cpp_open_class(char *classname, char *rname, int strip) +// +// Opens a new C++ class or structure. Basically, this just records +// the class name and clears a few variables. +// -------------------------------------------------------------------------- + +void PERL5::cpp_open_class(char *classname, char *rname, char *ctype, int strip) { + + char temp[256]; + extern void typeeq_addtypedef(char *, char *, DataType *); + + // Register this with the default class handler + + this->Language::cpp_open_class(classname, rname, ctype, strip); + + if (blessed) { + have_constructor = 0; + have_destructor = 0; + have_data_members = 0; + + // If the class is being renamed to something else, use the renaming + + if (rname) { + class_name = copy_string(rname); + class_renamed = 1; + // Now things get even more hideous. Need to register an equivalence + // between the renamed name and the new name. Yuck! + // printf("%s %s\n", classname, rname); + typeeq_addtypedef(classname,rname,0); + typeeq_addtypedef(rname,classname,0); + /* + fprintf(f_init,"\t SWIG_RegisterMapping(\"%s\",\"%s\",0);\n",classname,rname); + fprintf(f_init,"\t SWIG_RegisterMapping(\"%s\",\"%s\",0);\n",rname,classname); + */ + } else { + class_name = copy_string(classname); + class_renamed = 0; + } + + // A highly experimental feature. This is the fully qualified + // name of the Perl class + + if (!compat) { + fullclassname = realpackage; + fullclassname << "::" << class_name; + } else { + fullclassname = class_name; + } + + if(!hidden) + fullclassname = class_name; + + real_classname = copy_string(classname); + if (base_class) delete base_class; + base_class = 0; + class_type = copy_string(ctype); + pcode = new String(); + blessedmembers = new String(); + member_keys = new String(); + + // Add some symbols to the hash tables + + // classes.add(real_classname,copy_string(class_name)); /* Map original classname to class */ + classes.add(real_classname,copy_string(fullclassname)); /* Map original classname to class */ + + // Add full name of datatype to the hash table just in case the user uses it + + sprintf(temp,"%s %s", class_type, fullclassname.get()); + // classes.add(temp,copy_string(class_name)); /* Map full classname to classs */ + } +} + +// ------------------------------------------------------------------------------- +// PERL5::cpp_close_class() +// +// These functions close a class definition. +// +// This also sets up the hash table of classes we've seen go by. +// ------------------------------------------------------------------------------- + +void PERL5::cpp_close_class() { + + // We need to check to make sure we got constructors, and other + // stuff here. + + if (blessed) { + pm << "\n############# Class : " << fullclassname << " ##############\n"; + pm << "\npackage " << fullclassname << ";\n"; + + // If we are inheriting from a base class, set that up + + if (strcmp(class_name,realpackage)) + pm << "@ISA = qw( " << realpackage; + else + pm << "@ISA = qw( "; + + if (base_class) { + pm << " " << (hidden ? realpackage : "") << (hidden ? "::" : "") << *base_class; + } + pm << " );\n"; + + // Dump out a hash table containing the pointers that we own + + pm << "%OWNER = ();\n"; + if (have_data_members) { + pm << "%BLESSEDMEMBERS = (\n" + << blessedmembers->get() + << ");\n\n"; + } + if (have_data_members || have_destructor) + pm << "%ITERATORS = ();\n"; + + + // Dump out the package methods + + pm << *pcode; + delete pcode; + + // Output methods for managing ownership + + pm << "sub DISOWN {\n" + << tab4 << "my $self = shift;\n" + << tab4 << "my $ptr = tied(%$self);\n" + << tab4 << "delete $OWNER{$ptr};\n" + << tab4 << "};\n\n" + << "sub ACQUIRE {\n" + << tab4 << "my $self = shift;\n" + << tab4 << "my $ptr = tied(%$self);\n" + << tab4 << "$OWNER{$ptr} = 1;\n" + << tab4 << "};\n\n"; + + // Only output the following methods if a class has member data + + if (have_data_members) { + + // Output a FETCH method. This is actually common to all classes + pm << "sub FETCH {\n" + << tab4 << "my ($self,$field) = @_;\n" + << tab4 << "my $member_func = \"" << package << "::" << name_get(name_member("${field}",class_name,AS_IS),AS_IS) << "\";\n" + << tab4 << "my $val = &$member_func($self);\n" + << tab4 << "if (exists $BLESSEDMEMBERS{$field}) {\n" + << tab8 << "return undef if (!defined($val));\n" + << tab8 << "my %retval;\n" + << tab8 << "tie %retval,$BLESSEDMEMBERS{$field},$val;\n" + << tab8 << "return bless \\%retval, $BLESSEDMEMBERS{$field};\n" + << tab4 << "}\n" + << tab4 << "return $val;\n" + << "}\n\n"; + + // Output a STORE method. This is also common to all classes (might move to base class) + + pm << "sub STORE {\n" + << tab4 << "my ($self,$field,$newval) = @_;\n" + << tab4 << "my $member_func = \"" << package << "::" << name_set(name_member("${field}",class_name,AS_IS),AS_IS) << "\";\n" + << tab4 << "if (exists $BLESSEDMEMBERS{$field}) {\n" + << tab8 << "&$member_func($self,tied(%{$newval}));\n" + << tab4 << "} else {\n" + << tab8 << "&$member_func($self,$newval);\n" + << tab4 << "}\n" + << "}\n\n"; + + // Output a FIRSTKEY method. This is to allow iteration over a structure's keys. + + pm << "sub FIRSTKEY {\n" + << tab4 << "my $self = shift;\n" + << tab4 << "$ITERATORS{$self} = [" << member_keys->get() << "];\n" + << tab4 << "my $first = shift @{$ITERATORS{$self}};\n" + << tab4 << "return $first;\n" + << "}\n\n"; + + // Output a NEXTKEY method. This is the iterator so that each and keys works + + pm << "sub NEXTKEY {\n" + << tab4 << "my $self = shift;\n" + << tab4 << "$nelem = scalar @{$ITERATORS{$self}};\n" + << tab4 << "if ($nelem > 0) {\n" + << tab8 << "my $member = shift @{$ITERATORS{$self}};\n" + << tab8 << "return $member;\n" + << tab4 << "} else {\n" + << tab8 << "$ITERATORS{$self} = [" << member_keys->get() << "];\n" + << tab8 << "return ();\n" + << tab4 << "}\n" + << "}\n\n"; + } + } +} + +// -------------------------------------------------------------------------- +// PERL5::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) +// +// Handles a C++ member function. This basically does the same thing as +// the non-C++ version, but we set up a few status variables that affect +// the function generation function. +// +// -------------------------------------------------------------------------- + +void PERL5::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) { + + String func; + char *realname; + Parm *p; + int i; + String cname = "perl5:"; + int pcount, numopt; + char *tm; + + // First emit normal member function + + member_func = 1; + this->Language::cpp_member_func(name,iname,t,l); + member_func = 0; + + if (!blessed) return; + + // Now emit a Perl wrapper function around our member function, we might need + // to patch up some arguments along the way + + if (!iname) + realname = name; + else + realname = iname; + + cname << class_name << "::" << realname; + if (add_symbol(cname.get(),0,0)) { + return; // Forget it, we saw this function already + } + + func << "sub " << realname << " {\n" + << tab4 << "my @args = @_;\n" + << tab4 << "$args[0] = tied(%{$args[0]});\n"; + + // Now we have to go through and patch up the argument list. If any + // arguments to our function correspond to other Perl objects, we + // need to extract them from a tied-hash table object. + + p = l->get_first(); + pcount = l->nparms; + numopt = l->numopt(); + i = 1; + while(p) { + if (!p->ignore) { + String sourceNtarget; + sourceNtarget << "$args[" << i << "]"; + + if ((tm = typemap_lookup("perl5in","perl5",p->t,"",sourceNtarget,sourceNtarget))) + func << tm << "\n"; + // Look up the datatype name here + else if ((classes.lookup(p->t->name)) && (p->t->is_pointer <= 1)) { + // Yep. This smells alot like an object, patch up the arguments + + if (i >= (pcount - numopt)) + func << tab4 << "if (scalar(@args) >= " << i << ") {\n"; + + func << tab4 << "$args[" << i << "] = tied(%{$args[" << i << "]});\n"; + + if (i >= (pcount - numopt)) + func << tab4 << "}\n"; + } + i++; + } + p = l->get_next(); + } + + // Okay. We've made argument adjustments, now call into the package + + func << tab4 << "my $result = " << package << "::" << name_member(realname,class_name) + << "(@args);\n"; + + // Now check to see what kind of return result was found. + // If this function is returning a result by 'value', SWIG did an + // implicit malloc/new. We'll mark the object like it was created + // in Perl so we can garbage collect it. + + if ((tm = typemap_lookup("perl5out","perl5",t,"",name,"sv"))) { + func << tm << "\n" + << tab4 <<"return $result;\n" + << "}\n"; + } else if ((classes.lookup(t->name)) && (t->is_pointer <=1)) { + + func << tab4 << "return undef if (!defined($result));\n"; + + // If we're returning an object by value, put it's reference + // into our local hash table + + if ((t->is_pointer == 0) || ((t->is_pointer == 1) && NewObject)) { + func << tab4 << "$" << (char *) classes.lookup(t->name) << "::OWNER{$result} = 1;\n"; + } + + // We're returning a Perl "object" of some kind. Turn it into + // a tied hash + + func << tab4 << "my %resulthash;\n" + /* << tab4 << "tie %resulthash, \"" << (char *) classes.lookup(t->name) << "\", $result;\n" + << tab4 << "return bless \\%resulthash, \"" << (char *) classes.lookup(t->name) << "\";\n" */ + << tab4 << "tie %resulthash, ref($result), $result;\n" + << tab4 << "return bless \\%resulthash, ref($result);\n" + + << "}\n"; + + } else { + + // Hmmm. This doesn't appear to be anything I know about so just + // return it unmolested. + + func << tab4 <<"return $result;\n" + << "}\n"; + + } + + // Append our function to the pcode segment + + *pcode << func; + + // Create a new kind of documentation entry for the shadow class + + if (doc_entry) { + doc_entry->usage = ""; // Blow away whatever was there before + doc_entry->usage << usage_func(realname,t,l); + } +} + +// -------------------------------------------------------------------------------- +// PERL5::cpp_variable(char *name, char *iname, DataType *t) +// +// Adds an instance member. This is a little hairy because data members are +// really added with a tied-hash table that is attached to the object. +// +// On the low level, we will emit a pair of get/set functions to retrieve +// values just like before. These will then be encapsulated in a FETCH/STORE +// method associated with the tied-hash. +// +// In the event that a member is an object that we have already wrapped, then +// we need to retrieve the data a tied-hash as opposed to what SWIG normally +// returns. To determine this, we build an internal hash called 'BLESSEDMEMBERS' +// that contains the names and types of tied data members. If a member name +// is in the list, we tie it, otherwise, we just return the normal SWIG value. +// -------------------------------------------------------------------------------- + +void PERL5::cpp_variable(char *name, char *iname, DataType *t) { + + char *realname; + String cname = "perl5:"; + + // Emit a pair of get/set functions for the variable + + member_func = 1; + this->Language::cpp_variable(name, iname, t); + member_func = 0; + + if (iname) realname = iname; + else realname = name; + + if (blessed) { + cname << class_name << "::" << realname; + if (add_symbol(cname.get(),0,0)) { + return; // Forget it, we saw this already + } + + // Store name of key for future reference + + *member_keys << "'" << realname << "', "; + + // Now we need to generate a little Perl code for this + + if ((classes.lookup(t->name)) && (t->is_pointer <= 1)) { + + // This is a Perl object that we have already seen. Add an + // entry to the members list + + *blessedmembers << tab4 << realname << " => '" << (hidden ? realpackage : "") << (hidden ? "::" : "") << (char *) classes.lookup(t->name) << "',\n"; + + } + + // Patch up the documentation entry + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << "$this->{" << realname << "}"; + } + } + have_data_members++; +} + + +// ----------------------------------------------------------------------------- +// void PERL5::cpp_constructor(char *name, char *iname, ParmList *l) +// +// Emits a blessed constructor for our class. In addition to our construct +// we manage a Perl hash table containing all of the pointers created by +// the constructor. This prevents us from accidentally trying to free +// something that wasn't necessarily allocated by malloc or new +// ----------------------------------------------------------------------------- + +void PERL5::cpp_constructor(char *name, char *iname, ParmList *l) { + Parm *p; + int i; + char *realname; + String cname="perl5:constructor:"; + + // Emit an old-style constructor for this class + + member_func = 1; + this->Language::cpp_constructor(name, iname, l); + + if (blessed) { + + if (iname) + realname = iname; + else { + if (class_renamed) realname = class_name; + else realname = class_name; + } + + cname << class_name << "::" << realname; + if (add_symbol(cname.get(),0,0)) { + return; // Forget it, we saw this already + } + if ((strcmp(realname,class_name) == 0) || ((!iname) && (ObjCClass)) ){ + + // Emit a blessed constructor + + *pcode << "sub new {\n"; + + } else { + + // Constructor doesn't match classname so we'll just use the normal name + + *pcode << "sub " << name_construct(realname) << " () {\n"; + + } + + *pcode << tab4 << "my $self = shift;\n" + << tab4 << "my @args = @_;\n"; + + // We are going to need to patch up arguments here if necessary + // Now we have to go through and patch up the argument list. If any + // arguments to our function correspond to other Perl objects, we + // need to extract them from a tied-hash table object. + + p = l->get_first(); + i = 0; + while(p) { + + // Look up the datatype name here + + if ((classes.lookup(p->t->name)) && (p->t->is_pointer <= 1)) { + + // Yep. This smells alot like an object, patch up the arguments + *pcode << tab4 << "$args[" << i << "] = tied(%{$args[" << i << "]});\n"; + } + p = l->get_next(); + i++; + } + + *pcode << tab4 << "$self = " << package << "::" << name_construct(realname) << "(@args);\n" + << tab4 << "return undef if (!defined($self));\n" + << tab4 << "bless $self, \"" << fullclassname << "\";\n" + << tab4 << "$OWNER{$self} = 1;\n" + << tab4 << "my %retval;\n" + << tab4 << "tie %retval, \"" << fullclassname << "\", $self;\n" + << tab4 << "return bless \\%retval,\"" << fullclassname << "\";\n" + << "}\n\n"; + have_constructor = 1; + + // Patch up the documentation entry + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << usage_func("new",0,l); + } + } + member_func = 0; +} + + +// ------------------------------------------------------------------------------ +// void PERL5::cpp_destructor(char *name, char *newname) +// +// Creates a destructor for a blessed object +// ------------------------------------------------------------------------------ + +void PERL5::cpp_destructor(char *name, char *newname) { + + char *realname; + member_func = 1; + this->Language::cpp_destructor(name, newname); + + if (blessed) { + if (newname) realname = newname; + else { + if (class_renamed) realname = class_name; + else realname = name; + } + + // Emit a destructor for this object + + *pcode << "sub DESTROY {\n" + << tab4 << "my $self = tied(%{$_[0]});\n" + << tab4 << "delete $ITERATORS{$self};\n" + << tab4 << "if (exists $OWNER{$self}) {\n" + << tab8 << package << "::" << name_destroy(realname) << "($self);\n" + << tab8 << "delete $OWNER{$self};\n" + << tab4 << "}\n}\n\n"; + + have_destructor = 1; + + if (doc_entry) { + doc_entry->usage = "DESTROY"; + doc_entry->cinfo = "Destructor"; + } + } + member_func = 0; +} +// ----------------------------------------------------------------------------- +// void PERL5::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) +// +// Emits a wrapper for a static class function. Basically, we just call the +// appropriate method in the module package. +// ------------------------------------------------------------------------------ +void PERL5::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) { + this->Language::cpp_static_func(name,iname,t,l); + char *realname; + if (iname) realname = name; + else realname = iname; + + if (blessed) { + *pcode << "*" << realname << " = *" << realpackage << "::" << name_member(realname,class_name) << ";\n"; + } +} + +// ------------------------------------------------------------------------------ +// void PERL5::cpp_inherit(char **baseclass, int mode) +// +// This sets the Perl5 baseclass (if possible). +// ------------------------------------------------------------------------------ + +void PERL5::cpp_inherit(char **baseclass, int) { + + char *bc; + int i = 0, have_first = 0; + if (!blessed) { + this->Language::cpp_inherit(baseclass); + return; + } + + // Inherit variables and constants from base classes, but not + // functions (since Perl can handle that okay). + + this->Language::cpp_inherit(baseclass, INHERIT_CONST | INHERIT_VAR); + + // Now tell the Perl5 module that we're inheriting from base classes + + base_class = new String; + while (baseclass[i]) { + // See if this is a class we know about + bc = (char *) classes.lookup(baseclass[i]); + if (bc) { + if (have_first) *base_class << " "; + *base_class << bc; + have_first = 1; + } + i++; + } + if (!have_first) { + delete base_class; + base_class = 0; + } +} + +// -------------------------------------------------------------------------------- +// PERL5::cpp_declare_const(char *name, char *iname, DataType *type, char *value) +// +// Add access to a C++ constant. We can really just do this by hacking +// the symbol table +// -------------------------------------------------------------------------------- + +void PERL5::cpp_declare_const(char *name, char *iname, DataType *type, char *value) { + char *realname; + int oldblessed = blessed; + String cname; + + // Create a normal constant + blessed = 0; + this->Language::cpp_declare_const(name, iname, type, value); + blessed = oldblessed; + + if (blessed) { + if (!iname) + realname = name; + else + realname = iname; + + cname << class_name << "::" << realname; + if (add_symbol(cname.get(),0,0)) { + return; // Forget it, we saw this already + } + + // Create a symbol table entry for it + *pcode << "*" << realname << " = *" << package << "::" << name_member(realname,class_name) << ";\n"; + + // Fix up the documentation entry + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << realname; + if (value) { + doc_entry->usage << " = " << value; + } + } + } +} + +// ----------------------------------------------------------------------- +// PERL5::cpp_class_decl(char *name, char *rename, char *type) +// +// Treatment of an empty class definition. Used to handle +// shadow classes across modules. +// ----------------------------------------------------------------------- + +void PERL5::cpp_class_decl(char *name, char *rename, char *type) { + char temp[256]; + if (blessed) { + classes.add(name,copy_string(rename)); + // Add full name of datatype to the hash table + if (strlen(type) > 0) { + sprintf(temp,"%s %s", type, name); + classes.add(temp,copy_string(rename)); + } + } +} + +// -------------------------------------------------------------------------------- +// PERL5::add_typedef(DataType *t, char *name) +// +// This is called whenever a typedef is encountered. When shadow classes are +// used, this function lets us discovered hidden uses of a class. For example : +// +// struct FooBar { +// ... +// } +// +// typedef FooBar *FooBarPtr; +// +// -------------------------------------------------------------------------------- + +void PERL5::add_typedef(DataType *t, char *name) { + + if (!blessed) return; + + // First check to see if there aren't too many pointers + + if (t->is_pointer > 1) return; + + if (classes.lookup(name)) return; // Already added + + // Now look up the datatype in our shadow class hash table + + if (classes.lookup(t->name)) { + + // Yep. This datatype is in the hash + + // Put this types 'new' name into the hash + + classes.add(name,copy_string((char *) classes.lookup(t->name))); + } +} + + +// -------------------------------------------------------------------------------- +// PERL5::pragma(char *, char *, char *) +// +// Pragma directive. +// +// %pragma(perl5) code="String" # Includes a string in the .pm file +// %pragma(perl5) include="file.pl" # Includes a file in the .pm file +// +// -------------------------------------------------------------------------------- + +void PERL5::pragma(char *lang, char *code, char *value) { + if (strcmp(lang,"perl5") == 0) { + if (strcmp(code,"code") == 0) { + // Dump the value string into the .pm file + if (value) { + pragma_include << value << "\n"; + } + } else if (strcmp(code,"include") == 0) { + // Include a file into the .pm file + if (value) { + if (get_file(value,pragma_include) == -1) { + fprintf(stderr,"%s : Line %d. Unable to locate file %s\n", input_file, line_number,value); + } + } + } else { + fprintf(stderr,"%s : Line %d. Unrecognized pragma.\n", input_file,line_number); + } + } +} diff --git a/SWIG/Source/Modules1.1/perl5.h b/SWIG/Source/Modules1.1/perl5.h new file mode 100644 index 000000000..b8d8d7830 --- /dev/null +++ b/SWIG/Source/Modules1.1/perl5.h @@ -0,0 +1,109 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + +/************************************************************************** + * class PERL5 + * + * A Perl 5 implementation + **************************************************************************/ + +class PERL5 : public Language { +private: + int export_all; + char *package; + char *module; + String cmodule; + char *hide; + String chide; + String vinit; + FILE *f_pm; + String pm; // Package initialization code + String magic; // Magic variable wrappers + + char *perl_path; + int is_static; + void get_pointer(char *iname, char *srcname, char *src, char *dest, + DataType *t, String &f, char *ret); + char *usage_var(char *, DataType *); + char *usage_func(char *, DataType *, ParmList *); + char *usage_const(char *, DataType *, char *); + + char *alt_header; + +// The following variables are used to manage Perl5 classes + + int blessed; // Enable object oriented features + int hidden; // Every symbol hidden in package name + Hash classes; // A hash table for storing the classes we've seen so far + int have_constructor; + int have_destructor; + int have_data_members; + char *class_name; // Name of the class (what Perl thinks it is) + char *class_type; // Type of class "struct", "class", "union" + char *real_classname; // Real name of C/C++ class + String *base_class; // Base class (if using inheritance) + String *pcode; // Perl code associated with each class + String *blessedmembers; // Member data associated with each class + int member_func; // Set to 1 when wrapping a member function + char *realpackage; // Name of real module + String func_stubs; // Function stubs + String var_stubs; // Variable stubs + String *member_keys; // Keys for all member data + String exported; // Exported symbols + +public : + PERL5() { + package = 0; + module = 0; + perl_path = "perl5"; + is_static = 0; + blessed = 0; + hidden = 0; + alt_header = 0; + member_func = 0; + }; + void parse_args(int, char *argv[]); + void parse(); + void create_function(char *, char *, DataType *, ParmList *); + void link_variable(char *, char *, DataType *); + void declare_const(char *, char *, DataType *, char *); + void initialize(void); + void headers(void); + void close(void); + void set_module(char *, char **); + void set_init(char *); + void add_native(char *, char *); + void create_command(char *, char *); + char *type_mangle(DataType *); + + // Support for blessed perl thingies.... + + void cpp_open_class(char *classname, char *rename, char *ctype, int strip); + void cpp_close_class(); + void cpp_member_func(char *name, char *iname, DataType *t, ParmList *l); + void cpp_static_func(char *name, char *iname, DataType *t, ParmList *l); + void cpp_variable(char *name, char *iname, DataType *t); + void cpp_constructor(char *name, char *iname, ParmList *l); + void cpp_destructor(char *name, char *newname); + void cpp_inherit(char **baseclass, int mode = INHERIT_ALL); + void cpp_declare_const(char *name, char *iname, DataType *type, char *value); + void cpp_class_decl(char *, char *, char *); + void add_typedef(DataType *t, char *name); + void pragma(char *, char *, char *); + void import(char *filename); +}; + + + diff --git a/SWIG/Source/Modules1.1/pycpp.cxx b/SWIG/Source/Modules1.1/pycpp.cxx new file mode 100644 index 000000000..5aec6110d --- /dev/null +++ b/SWIG/Source/Modules1.1/pycpp.cxx @@ -0,0 +1,516 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/********************************************************************** + * $Header$ + * + * pycpp.cxx + * + * This module contains code to generate Python shadow classes of C/C++ + * objects. + **************************************************************************/ + + +#include "swig.h" +#include "python.h" + +static String *setattr; +static String *getattr; +static String *pyclass; +static String *construct; +static String *cinit; +static String *additional; +static int have_constructor; +static int have_destructor; +static int have_getattr; +static int have_setattr; +static int have_repr; +static char *class_name; +static char *class_type; +static char *real_classname; +static String *base_class; +static String base_getattr; +static String base_setattr; +static int class_renamed = 0; + +// -------------------------------------------------------------------------- +// PYTHON::cpp_open_class(char *classname, char *rname, char *ctype, int strip) +// +// Opens a new C++ class or structure. +// -------------------------------------------------------------------------- + +void PYTHON::cpp_open_class(char *classname, char *rname, char *ctype, int strip) { + + char temp[256]; + + this->Language::cpp_open_class(classname, rname, ctype, strip); + + if (shadow) { + /* Create new strings for building up a wrapper function */ + + setattr = new String(); + getattr = new String(); + pyclass = new String(); + construct = new String(); + cinit = new String(); + additional= new String(); + base_class = 0; + base_getattr = ""; + base_setattr = ""; + + + // *pyclass << "class " << rname << ":\n"; + *setattr << tab4 << "def __setattr__(self,name,value):\n"; + *getattr << tab4 << "def __getattr__(self,name):\n"; + have_constructor = 0; + have_destructor = 0; + have_getattr = 0; + have_setattr = 0; + have_repr = 0; + if (rname) { + class_name = copy_string(rname); + class_renamed = 1; + } else { + class_name = copy_string(classname); + class_renamed = 0; + } + } + + real_classname = copy_string(classname); + class_type = copy_string(ctype); + + // Build up the hash table + hash.add(real_classname,copy_string(class_name)); + + sprintf(temp,"%s %s", class_type, real_classname); + hash.add(temp,copy_string(class_name)); + +} + +// -------------------------------------------------------------------------- +// PYTHON::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) +// +// Creates a C++ member function +// -------------------------------------------------------------------------- + +void PYTHON::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) { + + Parm *p; + int i; + char *realname; + int oldshadow; + int pcount; + int numopt; + int have_optional; + + String cname = "python:"; + String translate = ""; + + // Create the default member function + + oldshadow = shadow; // Disable shadowing when wrapping member functions + if (shadow) shadow = shadow | PYSHADOW_MEMBER; + this->Language::cpp_member_func(name,iname,t,l); + shadow = oldshadow; + if (shadow) { + if (!iname) + realname = name; + else + realname = iname; + + // Check to see if we've already seen this + cname << class_name << "::" << realname; + if (add_symbol(cname.get(), 0,0)) { + return; // Forget it, already saw it + } + + if (strcmp(realname,"__repr__") == 0) + have_repr = 1; + + // Now add it to the class + + *pyclass << tab4 << "def " << realname << "(self, *_args, **_kwargs):\n"; + // Create a doc string + if (docstring && doc_entry) { + *pyclass << tab8 << "\"\"\"" << add_docstring(doc_entry) << "\"\"\"\n"; + } + *pyclass << tab8 << "val = apply(" << module << "." << name_member(realname,class_name) << ",(self,) + _args, _kwargs)\n"; + + // Check to see if the return type is an object + if ((hash.lookup(t->name)) && (t->is_pointer <= 1)) { + if (!typemap_check("out",typemap_lang,t,name_member(realname,class_name))) { + if (!have_output) { + *pyclass << tab8 << "if val: val = " << (char *) hash.lookup(t->name) << "Ptr(val) "; + if (((hash.lookup(t->name)) && (t->is_pointer < 1)) || + ((hash.lookup(t->name)) && (t->is_pointer == 1) && NewObject)) + *pyclass << "; val.thisown = 1\n"; + else + *pyclass << "\n"; + } else { + // Do nothing! + } + } + } + emitAddPragmas(*pyclass, realname, tab8); + *pyclass << tab8 << "return val\n"; + + // Change the usage string to reflect our shadow class + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << usage_func(realname,t,l); + } + } +} + +// ----------------------------------------------------------------------------- +// void PYTHON::cpp_constructor(char *name, char *iname, ParmList *l) +// +// Make a constructor for our class +// ----------------------------------------------------------------------------- + +void PYTHON::cpp_constructor(char *name, char *iname, ParmList *l) { + char *realname; + Parm *p; + int i; + int oldshadow = shadow; + String cname = "python:constructor:"; + String translate = ""; + int pcount, numopt; + int have_optional; + + if (shadow) shadow = shadow | PYSHADOW_MEMBER; + this->Language::cpp_constructor(name,iname,l); + shadow = oldshadow; + + if (shadow) { + if (iname) + realname = iname; + else { + if (class_renamed) realname = class_name; + else realname = class_name; + } + + // Check to see if we've already seen this + cname << class_name << "::" << realname; + if (add_symbol(cname.get(), 0,0)) { + return; // Forget it, already seen it + } + + if (!have_constructor) { + + // Create a new constructor + + *construct << tab4 << "def __init__(self,*_args,**_kwargs):\n"; + if (docstring && doc_entry) + *construct << tab8 << "\"\"\"" << add_docstring(doc_entry) << "\"\"\"\n"; + + *construct << tab8 << "self.this = apply(" << module << "." << name_construct(realname) << ",_args,_kwargs)\n"; + *construct << tab8 << "self.thisown = 1\n"; + emitAddPragmas(*construct,"__init__",tab8); + have_constructor = 1; + } else { + + // Hmmm. We seem to be creating a different constructor. We're just going to create a + // function for it. + + *additional << "def " << realname << "(*_args,**_kwargs):\n"; + *additional << tab4 << "val = " << class_name << "Ptr(apply(" + << module << "." << name_construct(realname) << ",_args,_kwargs))\n" + << tab4 << "val.thisown = 1\n" + << tab4 << "return val\n\n"; + } + // Patch up the documentation entry + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << usage_func(class_name,0,l); + } + } +} + +// ------------------------------------------------------------------------------ +// void PYTHON::cpp_destructor(char *name, char *newname) +// +// Creates a destructor for this object +// ------------------------------------------------------------------------------ + +void PYTHON::cpp_destructor(char *name, char *newname) { + char *realname; + int oldshadow = shadow; + + if (shadow) shadow = shadow | PYSHADOW_MEMBER; + this->Language::cpp_destructor(name,newname); + shadow = oldshadow; + if (shadow) { + if (newname) realname = newname; + else { + if (class_renamed) realname = class_name; + else realname = name; + } + + *pyclass << tab4 << "def __del__(self," << module << "=" << module << "):\n"; + emitAddPragmas(*pyclass,"__del__",tab8); + *pyclass << tab8 << "if self.thisown == 1 :\n" + << tab8 << tab4 << module << "." << name_destroy(realname) << "(self)\n"; + + have_destructor = 1; + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << "del this"; + } + } +} + +// ------------------------------------------------------------------------------- +// PYTHON::cpp_close_class() +// +// Closes a Python class and writes out a wrapper +// ------------------------------------------------------------------------------- + +void PYTHON::cpp_close_class() { + String ptrclass; + String repr; + + if (shadow) { + + if (!have_constructor) { + // Build a constructor that takes a pointer to this kind of object + *construct << tab4 << "def __init__(self,this):\n"; + *construct << tab8 << "self.this = this\n"; + } + + // First, build the pointer base class + if (base_class) { + ptrclass << "class " << class_name << "Ptr(" << *base_class << "):\n"; + } else { + ptrclass << "class " << class_name << "Ptr :\n"; + } + + // *getattr << tab8 << "return self.__dict__[name]\n"; + *getattr << tab8 << "raise AttributeError,name\n"; + *setattr << tab8 << "self.__dict__[name] = value\n"; + + ptrclass << *cinit + << tab4 << "def __init__(self,this):\n" + << tab8 << "self.this = this\n" + << tab8 << "self.thisown = 0\n"; + + classes << ptrclass + << *pyclass; + if (have_setattr) + classes << *setattr; + if (have_getattr) + classes << *getattr; + + if (!have_repr) { + // Supply a repr method for this class + repr << tab4 << "def __repr__(self):\n" + << tab8 << "return \"\" % (self.this,)\n"; + + classes << repr; + emitAddPragmas(classes,"__class__",tab4); + } + + // Now build the real class with a normal constructor + + classes << "class " << class_name << "(" << class_name << "Ptr):\n"; + + if (docstring && doc_entry) { + classes << tab4 << "\"\"\"" << add_docstring(doc_entry) << "\"\"\"\n"; + } + + classes << *construct << "\n\n" + << "\n" << *additional << "\n"; + + delete pyclass; + delete setattr; + delete getattr; + delete additional; + } +} + +void PYTHON::cpp_cleanup() { }; + +void PYTHON::cpp_inherit(char **baseclass,int) { + + char *bc; + int i = 0, first_base = 0; + + if (!shadow) { + this->Language::cpp_inherit(baseclass); + return; + } + + // We'll inherit variables and constants, but not methods + + this->Language::cpp_inherit(baseclass, INHERIT_VAR); + + if (!baseclass) return; + base_class = new String; + + // Now tell the Python module that we're inheriting from a base class + + while (baseclass[i]) { + bc = (char *) hash.lookup(baseclass[i]); + if (bc) { + if (first_base) *base_class << ","; + *base_class << bc << "Ptr"; + first_base = 1; + } + i++; + } + if (!first_base) { + delete base_class; + base_class = 0; + } +} + +// -------------------------------------------------------------------------------- +// PYTHON::cpp_variable(char *name, char *iname, DataType *t) +// +// Adds an instance member. +// -------------------------------------------------------------------------------- + +void PYTHON::cpp_variable(char *name, char *iname, DataType *t) { + char *realname; + int inhash = 0; + int oldshadow = shadow; + String cname = "python:"; + + if (shadow) shadow = shadow | PYSHADOW_MEMBER; + this->Language::cpp_variable(name,iname,t); + shadow = oldshadow; + + if (shadow) { + have_getattr = 1; + have_setattr = 1; + if (!iname) + realname = name; + else + realname = iname; + + // Check to see if we've already seen this + + cname << class_name << "::" << realname; + if (add_symbol(cname.get(), 0,0)) { + return; // Forget it, already seen it + } + + // Figure out if we've seen this datatype before + + if ((hash.lookup(t->name)) && (t->is_pointer <= 1)) inhash = 1; + + // Now write some code to set the variable + *setattr << tab8 << "if name == \"" << realname << "\" :\n"; + if (inhash) { + *setattr << tab8 << tab4 << module << "." << name_set(name_member(realname,class_name)) << "(self,value.this)\n"; + } else { + *setattr << tab8 << tab4 << module << "." << name_set(name_member(realname,class_name)) << "(self,value)\n"; + } + *setattr << tab8 << tab4 << "return\n"; + + // Write some code to get the variable + *getattr << tab8 << "if name == \"" << realname << "\" : \n"; + if (inhash) { + *getattr << tab8 << tab4 << "return " << (char *) hash.lookup(t->name) << "Ptr(" << module << "." + << name_get(name_member(realname,class_name)) << "(self))\n"; + } else { + *getattr << tab8 << tab4 << "return " << module << "." << name_get(name_member(realname,class_name)) << "(self)\n"; + } + + // Patch up ye old documentation entry + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << "self." << realname; + } + } +} + +// -------------------------------------------------------------------------------- +// PYTHON::cpp_declare_const(char *name, char *iname, DataType *type, char *value) +// +// Add access to a C++ constant +// -------------------------------------------------------------------------------- + +void PYTHON::cpp_declare_const(char *name, char *iname, DataType *type, char *value) { + char *realname; + int oldshadow = shadow; + String cname = "python:"; + + if (shadow) shadow = shadow | PYSHADOW_MEMBER; + this->Language::cpp_declare_const(name,iname,type,value); + shadow = oldshadow; + + if (shadow) { + if (!iname) + realname = name; + else + realname = iname; + + // Check to see if we've already seen this + + cname << class_name << "::" << realname; + if (add_symbol(cname.get(), 0,0)) { + return; // Forget it, already seen it + } + + *cinit << tab4 << realname << " = " << module << "." << name_member(realname,class_name) << "\n"; + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << "self." << realname; + if (value) { + doc_entry->usage << " = " << value; + } + } + } +} + +// -------------------------------------------------------------------------------- +// PYTHON::add_typedef(DataType *t, char *name) +// +// This is called whenever a typedef is encountered. When shadow classes are +// used, this function lets us discovered hidden uses of a class. For example : +// +// struct FooBar { +// ... +// } +// +// typedef FooBar *FooBarPtr; +// +// -------------------------------------------------------------------------------- + +void PYTHON::add_typedef(DataType *t, char *name) { + + if (!shadow) return; + + // First check to see if there aren't too many pointers + + if (t->is_pointer > 1) return; + + if (hash.lookup(name)) return; // Already added + + + // Now look up the datatype in our shadow class hash table + + if (hash.lookup(t->name)) { + + // Yep. This datatype is in the hash + + // Put this types 'new' name into the hash + + hash.add(name,copy_string((char *) hash.lookup(t->name))); + } +} diff --git a/SWIG/Source/Modules1.1/python.cxx b/SWIG/Source/Modules1.1/python.cxx new file mode 100644 index 000000000..53402419d --- /dev/null +++ b/SWIG/Source/Modules1.1/python.cxx @@ -0,0 +1,1635 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/********************************************************************** + * $Header$ + * + * python.cxx + * + * Python module. + **************************************************************************/ + + +#include "swig.h" +#include "python.h" + +// Structures for managing doc strings + +struct DocString { + DocEntry *de; + char *name; + DocString *next; +}; + +static int doc_index = 0; +static DocString *doc_strings = 0; + +static char *usage = "\ +Python Options (available with -python)\n\ + -docstring - Produce docstrings (only applies to shadow classes)\n\ + -globals name - Set name used to access C global variable ('cvar' by default).\n\ + -module name - Set module name\n\ + -keyword - Use keyword arguments\n\ + -shadow - Generate shadow classes. \n\n"; + +static String pragma_include; + +// --------------------------------------------------------------------- +// PYTHON::parse_args(int argc, char *argv[]) +// +// --------------------------------------------------------------------- + +void PYTHON::parse_args(int argc, char *argv[]) { + + int i = 1; + + sprintf(LibDir,"%s",path); + + docstring = 0; + + // Look for additional command line options. + for (i = 1; i < argc; i++) { + if (argv[i]) { + if(strcmp(argv[i],"-module") == 0) { + if (argv[i+1]) { + module = new char[strlen(argv[i+1])+2]; + strcpy(module, argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i+=1; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-globals") == 0) { + if (argv[i+1]) { + global_name = new char[strlen(argv[i+1])+1]; + strcpy(global_name, argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-shadow") == 0) { + shadow = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-docstring") == 0) { + docstring = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-keyword") == 0) { + use_kw = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-help") == 0) { + fputs(usage,stderr); + } + } + } + // Create a symbol for this language + add_symbol("SWIGPYTHON",0,0); + + // Set name of typemaps + + typemap_lang = "python"; + +} + +// --------------------------------------------------------------------- +// PYTHON::parse() +// +// Parse the interface file +// --------------------------------------------------------------------- + +void +PYTHON::parse() { + + printf("Generating wrappers for Python\n"); + headers(); + + // Run the SWIG parser + + yyparse(); +} + +// --------------------------------------------------------------------- +// PYTHON::set_module(char *mod_name, char **mod_list) +// +// Sets the module name. +// Does nothing if it's already set (so it can be overridden as a command +// line option). +// +//---------------------------------------------------------------------- + +void PYTHON::set_module(char *mod_name, char **mod_list) { + int i; + + // If an "import" method has been set and we're in shadow class mode, + // output a python command to load the module + + if (import_file) { + if (!(strcmp(import_file,input_file+strlen(input_file)-strlen(import_file)))) { + if (shadow) { + fprintf(f_shadow,"\nfrom %s import *\n", mod_name); + } + delete import_file; + import_file = 0; + } + } + + if (module) return; + + module = new char[strlen(mod_name)+1]; + strcpy(module,mod_name); + + // If there was a mod_list specified, make this incredible hack + if (mod_list) { + modinit << "#define SWIGMODINIT "; + modextern << "#ifdef __cplusplus\n" + << "extern \"C\" {\n" + << "#endif\n"; + i = 0; + while(mod_list[i]) { + modinit << "swig_add_module(\"" << mod_list[i] << "\",init" + << mod_list[i] << "); \\\n"; + + modextern << "extern void init" << mod_list[i] << "();\n"; + i++; + } + modextern << "#ifdef __cplusplus\n" + << "}\n" + << "#endif\n"; + modinit << "/* End of extern module initialization */\n"; + + } +} + +// --------------------------------------------------------------------- +// PYTHON::set_init(char *iname) +// +// Sets the initialization function name. +// Does nothing if it's already set +// +//---------------------------------------------------------------------- + +void PYTHON::set_init(char *iname) { + set_module(iname,0); +} + + +// --------------------------------------------------------------------- +// PYTHON::import(char *filename) +// +// Imports a SWIG module as a separate file. +//---------------------------------------------------------------------- + +void PYTHON::import(char *filename) { + if (import_file) delete import_file; + import_file = copy_string(filename); +} + +// ---------------------------------------------------------------------- +// PYTHON::add_method(char *name, char *function) +// +// Add some symbols to the methods table +// ---------------------------------------------------------------------- + +void PYTHON::add_method(char *name, char *function) { + + Method *n; + + n = new Method; + n->name = new char[strlen(name)+1]; + strcpy(n->name,name); + n->function = new char[strlen(function)+1]; + strcpy(n->function, function); + + n->next = head; + head = n; +} + +// --------------------------------------------------------------------- +// PYTHON::print_methods() +// +// Prints out the method array. +// --------------------------------------------------------------------- + +void PYTHON::print_methods() { + + Method *n; + + fprintf(f_wrappers,"static PyMethodDef %sMethods[] = {\n", module); + n = head; + while (n) { + if (!use_kw) { + fprintf(f_wrappers,"\t { \"%s\", %s, METH_VARARGS },\n", n->name, n->function); + } else { + fprintf(f_wrappers,"\t { \"%s\", (PyCFunction) %s, METH_VARARGS | METH_KEYWORDS },\n", n->name, n->function); + } + n = n->next; + } + fprintf(f_wrappers,"\t { NULL, NULL }\n"); + fprintf(f_wrappers,"};\n"); + fprintf(f_wrappers,"#ifdef __cplusplus\n"); + fprintf(f_wrappers,"}\n"); + fprintf(f_wrappers,"#endif\n"); +} + +// --------------------------------------------------------------------- +// char *PYTHON::add_docstring(DocEntry *de) +// +// Adds a documentation entry to the doc-string generator. Returns a +// unique character symbol that will be used to fill in the doc-string +// at a later time. +// --------------------------------------------------------------------- + +char *PYTHON::add_docstring(DocEntry *de) { + DocString *s; + String str; + + str = "@doc"; + str << doc_index << "@"; + + s = new DocString(); + s->de = de; + s->name = copy_string(str); + s->next = doc_strings; + doc_strings = s; + doc_index++; + return s->name; +} + +// --------------------------------------------------------------------- +// PYTHON::headers(void) +// +// ---------------------------------------------------------------------- + +void PYTHON::headers(void) +{ + + emit_banner(f_header); + + fprintf(f_header,"/* Implementation : PYTHON */\n\n"); + fprintf(f_header,"#define SWIGPYTHON\n"); + + if (NoInclude) + fprintf(f_header,"#define SWIG_NOINCLUDE\n"); + + if (insert_file("python.swg", f_header) == -1) { + fprintf(stderr,"SWIG : Fatal error. Unable to locate python.swg. (Possible installation problem).\n"); + SWIG_exit(1); + } +} + + +// -------------------------------------------------------------------- +// PYTHON::initialize(void) +// +// This function outputs the starting code for a function to initialize +// your interface. It is only called once by the parser. +// +// --------------------------------------------------------------------- + +void PYTHON::initialize(void) +{ + + char filen[256]; + char *temp; + char *oldmodule = 0; + + if (!module) { + module = "swig"; + fprintf(stderr,"SWIG : *** Warning. No module name specified.\n"); + } + + // If shadow classing is enabled, we're going to change the module + // name to "modulec" + + if (shadow) { + temp = new char[strlen(module)+2]; + sprintf(temp,"%sc",module); + oldmodule = module; + module = temp; + } + /* Initialize the C code for the module */ + initialize_cmodule(); + /* Create a shadow file (if enabled).*/ + if (shadow) { + sprintf(filen,"%s%s.py", output_dir, oldmodule); + if ((f_shadow = fopen(filen,"w")) == 0) { + fprintf(stderr,"Unable to open %s\n", filen); + SWIG_exit(0); + } + fprintf(f_shadow,"# This file was created automatically by SWIG.\n"); + fprintf(f_shadow,"import %s\n", module); + } + + // Dump out external module declarations + + if (strlen(modinit.get()) > 0) { + fprintf(f_header,"%s\n",modinit.get()); + } + if (strlen(modextern.get()) > 0) { + fprintf(f_header,"%s\n",modextern.get()); + } + fprintf(f_wrappers,"#ifdef __cplusplus\n"); + fprintf(f_wrappers,"extern \"C\" {\n"); + fprintf(f_wrappers,"#endif\n"); +} + +// --------------------------------------------------------------------- +// PYTHON::initialize_cmodule(void) +// +// Initializes the C module. +// +// --------------------------------------------------------------------- +void PYTHON::initialize_cmodule(void) +{ + int i; + fprintf(f_header,"#define SWIG_init init%s\n\n", module); + fprintf(f_header,"#define SWIG_name \"%s\"\n", module); + + // Output the start of the init function. + // Modify this to use the proper return type and arguments used + // by the target Language + + fprintf(f_init,"static PyObject *SWIG_globals;\n"); + + fprintf(f_init,"#ifdef __cplusplus\n"); + fprintf(f_init,"extern \"C\" \n"); + fprintf(f_init,"#endif\n"); + + fprintf(f_init,"SWIGEXPORT(void) init%s() {\n",module); + fprintf(f_init,"\t PyObject *m, *d;\n"); + + if (InitNames) { + i = 0; + while (InitNames[i]) { + fprintf(f_init,"\t %s();\n", InitNames[i]); + i++; + } + } + fprintf(f_init,"\t SWIG_globals = SWIG_newvarlink();\n"); + fprintf(f_init,"\t m = Py_InitModule(\"%s\", %sMethods);\n", module, module); + fprintf(f_init,"\t d = PyModule_GetDict(m);\n"); +} + + +// --------------------------------------------------------------------- +// PYTHON::close(void) +// +// Called when the end of the interface file is reached. Closes the +// initialization function and performs cleanup as necessary. +// --------------------------------------------------------------------- + +void PYTHON::close(void) +{ + + print_methods(); + close_cmodule(); + if ((doc_entry) && (module)){ + String temp; + temp << "Python Module : "; + if (shadow) { + module[strlen(module)-1] = 0; + } + temp << module; + doc_entry->cinfo << temp; + } + if (shadow) { + String fullshadow; + fullshadow << classes + << "\n\n#-------------- FUNCTION WRAPPERS ------------------\n\n" + << func + << "\n\n#-------------- VARIABLE WRAPPERS ------------------\n\n" + << vars; + + if (strlen(pragma_include) > 0) { + fullshadow << "\n\n#-------------- USER INCLUDE -----------------------\n\n" + << pragma_include; + } + + // Go through all of the docstrings and replace the docstrings + + DocString *s; + s = doc_strings; + while (s) { + fullshadow.replace(s->name, s->de->text); + s = s->next; + } + /* + fprintf(f_shadow,"\n\n#-------------- FUNCTION WRAPPERS ------------------\n\n"); + fprintf(f_shadow,"%s",func.get()); + fprintf(f_shadow,"\n\n#-------------- VARIABLE WRAPPERS ------------------\n\n"); + fprintf(f_shadow,"%s",vars.get()); + if (strlen(pragma_include) > 0) { + fprintf(f_shadow,"\n\n#-------------- USER INCLUDE -----------------------\n\n"); + fprintf(f_shadow,"%s",pragma_include.get()); + } + */ + fprintf(f_shadow, "%s", fullshadow.get()); + fclose(f_shadow); + } +} + +// -------------------------------------------------------------------- +// PYTHON::close_cmodule(void) +// +// Called to cleanup the C module code +// -------------------------------------------------------------------- +void PYTHON::close_cmodule(void) +{ + emit_ptr_equivalence(f_init); + fprintf(f_init,"}\n"); +} + +// ---------------------------------------------------------------------- +// PYTHON::get_pointer(char *iname, char *srcname, char *src, char *target, +// DataType *t, WrapperFunction &f, char *ret) +// +// Emits code to get a pointer and do type checking. +// iname = name of the function/method (used for error messages) +// srcname = Name of source (used for error message reporting). +// src = name of variable where source string is located. +// dest = name of variable where pointer value is stored. +// t = Expected datatype of the parameter +// f = Wrapper function object being used to generate code. +// ret = return code upon failure. +// +// Note : pointers are stored as strings so you first need to get +// a string and then call _swig_get_hex() to extract a point. +// +// This module is pretty ugly, but type checking is kind of nasty +// anyways. +// ---------------------------------------------------------------------- + +void +PYTHON::get_pointer(char *iname, char *srcname, char *src, char *dest, + DataType *t, String &f, char *ret) +{ + + // Now get the pointer value from the string and save in dest + + f << tab4 << "if (" << src << ") {\n" + << tab8 << "if (" << src << " == Py_None) { " << dest << " = NULL; }\n" + << tab8 << "else if (SWIG_GetPtrObj(" << src << ",(void **) &" << dest << ","; + + // If we're passing a void pointer, we give the pointer conversion a NULL + // pointer, otherwise pass in the expected type. + + if (t->type == T_VOID) f << "(char *) 0 )) {\n"; + else + f << "\"" << t->print_mangle() << "\")) {\n"; + + // This part handles the type checking according to three different + // levels. 0 = no checking, 1 = warning message, 2 = strict. + + switch(TypeStrict) { + case 0: // No type checking + f << tab8 << "}\n"; + break; + + case 1: // Warning message only + + // Change this part to how you want to handle a type-mismatch warning. + // By default, it will just print to stderr. + + f << tab8 << tab4 << "fprintf(stderr,\"Warning : type mismatch in " << srcname + << " of " << iname << ". Expected " << t->print_mangle() + << ", received %s\\n\"," << src << ");\n" + << tab8 << "}\n"; + + break; + case 2: // Super strict mode. + + // Change this part to return an error. + + f << tab8 << tab4 << "PyErr_SetString(PyExc_TypeError,\"Type error in " << srcname + << " of " << iname << ". Expected " << t->print_mangle() << ".\");\n" + << tab8 << "return " << ret << ";\n" + << tab8 << "}\n"; + break; + + default : + fprintf(stderr,"SWIG Error. Unknown strictness level\n"); + break; + } + f << tab4 << "}\n"; +} + +// ---------------------------------------------------------------------- +// PYTHON::emit_function_header() +// +// Return the code to be used as a function header +// ---------------------------------------------------------------------- +void PYTHON::emit_function_header(WrapperFunction &emit_to, char *wname) +{ + if (!use_kw) { + emit_to.def << "static PyObject *" << wname + << "(PyObject *self, PyObject *args) {"; + } else { + emit_to.def << "static PyObject *" << wname + << "(PyObject *self, PyObject *args, PyObject *kwargs) {"; + } + emit_to.code << tab4 << "self = self;\n"; +} + +// ---------------------------------------------------------------------- +// PYTHON::convert_self() +// +// Called during the function generation process, to determine what to +// use as the "self" variable during the call. Derived classes may emit code +// to convert the real self pointer into a usable pointer. +// +// Returns the name of the variable to use as the self pointer +// ---------------------------------------------------------------------- +char *PYTHON::convert_self(WrapperFunction &) +{ + // Default behaviour is no translation + return ""; +} + +// ---------------------------------------------------------------------- +// PYTHON::make_funcname_wrapper() +// +// Called to create a name for a wrapper function +// ---------------------------------------------------------------------- +char *PYTHON::make_funcname_wrapper(char *fnName) +{ + return name_wrapper(fnName,""); +} + +// ---------------------------------------------------------------------- +// PYTHON::create_command(char *cname, char *iname) +// +// Create a new command in the interpreter. Used for C++ inheritance +// stuff. +// ---------------------------------------------------------------------- + +void PYTHON::create_command(char *cname, char *iname) { + + // Create the name of the wrapper function + + char *wname = name_wrapper(cname,""); + + // Now register the function with the interpreter. + + add_method(iname, wname); + +} + +// ---------------------------------------------------------------------- +// PYTHON::create_function(char *name, char *iname, DataType *d, +// ParmList *l) +// +// This function creates a wrapper function and registers it with the +// interpreter. +// +// Inputs : +// name = actual name of the function that's being wrapped +// iname = name of the function in the interpreter (may be different) +// d = Return datatype of the functions. +// l = A linked list containing function parameter information. +// +// ---------------------------------------------------------------------- + +void PYTHON::create_function(char *name, char *iname, DataType *d, ParmList *l) +{ + Parm *p; + int pcount,i,j; + String wname, self_name, call_name; + char source[64], target[64], temp[256], argnum[20]; + char *usage = 0; + WrapperFunction f; + String parse_args; + String arglist; + String get_pointers; + String cleanup, outarg; + String check; + String build; + String kwargs; + + int have_build = 0; + char *tm; + int numopt = 0; + + have_output = 0; + + // Make a valid name for this function. This removes special symbols + // that would cause problems in the C compiler. + + wname = make_funcname_wrapper(iname); + + // Now emit the function declaration for the wrapper function. You + // should modify this to return the appropriate types and use the + // appropriate parameters. + + emit_function_header(f, wname); + + f.add_local("PyObject *","_resultobj"); + + // Get the function usage string for later use + + usage = usage_func(iname,d,l); + + // Write code to extract function parameters. + // This is done in one pass, but we need to construct three independent + // pieces. + // 1. Python format string such as "iis" + // 2. The actual arguments to put values into + // 3. Pointer conversion code. + // + // If there is a type mapping, we will extract the Python argument + // as a raw PyObject and let the user deal with it. + // + + pcount = emit_args(d, l, f); + if (!use_kw) { + parse_args << tab4 << "if(!PyArg_ParseTuple(args,\""; + } else { + parse_args << tab4 << "if(!PyArg_ParseTupleAndKeywords(args,kwargs,\""; + arglist << ",_kwnames"; + } + + i = 0; + j = 0; + numopt = l->numopt(); // Get number of optional arguments + if (numopt) have_defarg = 1; + p = l->get_first(); + + kwargs << "{ "; + while (p != 0) { + + // Generate source and target strings + sprintf(source,"_obj%d",i); + sprintf(target,"_arg%d",i); + sprintf(argnum,"%d",j+1); + + // Only consider this argument if it's not ignored + + if (!p->ignore) { + arglist << ","; + // Add an optional argument separator if needed + + if (j == pcount-numopt) { + parse_args << "|"; + } + + if (strlen(p->name)) { + kwargs << "\"" << p->name << "\","; + } else { + kwargs << "\"arg" << j+1 << "\","; + // kwargs << "\"\","; + } + + // Look for input typemap + + if ((tm = typemap_lookup("in","python",p->t,p->name,source,target,&f))) { + parse_args << "O"; // Grab the argument as a raw PyObject + f.add_local("PyObject *",source,"0"); + arglist << "&" << source; + if (i >= (pcount-numopt)) + get_pointers << tab4 << "if (" << source << ")\n"; + get_pointers << tm << "\n"; + get_pointers.replace("$argnum", argnum); + get_pointers.replace("$arg",source); + } else { + + // Check if this parameter is a pointer. If not, we'll get values + + if (!p->t->is_pointer) { + // Extract a parameter by "value" + + switch(p->t->type) { + + // Handle integers here. Usually this can be done as a single + // case if you appropriate cast things. However, if you have + // special cases, you'll need to add more code. + + case T_INT : case T_UINT: case T_SINT: + parse_args << "i"; + break; + case T_SHORT: case T_USHORT: case T_SSHORT: + parse_args << "h"; + break; + case T_LONG : case T_ULONG: case T_SLONG : + parse_args << "l"; + break; + case T_SCHAR : case T_UCHAR : + parse_args << "b"; + break; + case T_CHAR: + parse_args << "c"; + break; + case T_FLOAT : + parse_args << "f"; + break; + case T_DOUBLE: + parse_args << "d"; + break; + + case T_BOOL: + { + String tempb; + String tempval; + if (p->defvalue) { + tempval << "(int) " << p->defvalue; + } + tempb << "tempbool" << i; + parse_args << "i"; + if (!p->defvalue) + f.add_local("int",tempb.get()); + else + f.add_local("int",tempb.get(),tempval.get()); + get_pointers << tab4 << target << " = " << p->t->print_cast() << " " << tempb << ";\n"; + arglist << "&" << tempb; + } + break; + + // Void.. Do nothing. + + case T_VOID : + break; + + // User defined. This is usually invalid. No way to pass a + // complex type by "value". We'll just pass into the unsupported + // datatype case. + + case T_USER: + + // Unsupported data type + + default : + fprintf(stderr,"%s : Line %d. Unable to use type %s as a function argument.\n",input_file, line_number, p->t->print_type()); + break; + } + + // Emit code for parameter list + + if ((p->t->type != T_VOID) && (p->t->type != T_BOOL)) + arglist << "&_arg" << i; + + } else { + + // Is some other kind of variable. + + if ((p->t->type == T_CHAR) && (p->t->is_pointer == 1)) { + parse_args << "s"; + arglist << "&_arg" << i; + } else { + + // Have some sort of pointer variable. Create a temporary local + // variable for the string and read the pointer value into it. + + parse_args << "O"; + sprintf(source,"_argo%d", i); + sprintf(target,"_arg%d", i); + sprintf(temp,"argument %d",i+1); + + f.add_local("PyObject *", source,"0"); + arglist << "&" << source; + get_pointer(iname, temp, source, target, p->t, get_pointers, "NULL"); + } + } + } + j++; + } + // Check if there was any constraint code + if ((tm = typemap_lookup("check","python",p->t,p->name,source,target))) { + check << tm << "\n"; + check.replace("$argnum", argnum); + } + // Check if there was any cleanup code + if ((tm = typemap_lookup("freearg","python",p->t,p->name,target,source))) { + cleanup << tm << "\n"; + cleanup.replace("$argnum", argnum); + cleanup.replace("$arg",source); + } + if ((tm = typemap_lookup("argout","python",p->t,p->name,target,"_resultobj"))) { + outarg << tm << "\n"; + outarg.replace("$argnum", argnum); + outarg.replace("$arg",source); + have_output++; + } + if ((tm = typemap_lookup("build","python",p->t,p->name,source,target))) { + build << tm << "\n"; + have_build = 1; + } + p = l->get_next(); + i++; + } + + kwargs << " NULL }"; + if (use_kw) { + f.locals << tab4 << "char *_kwnames[] = " << kwargs << ";\n"; + } + + parse_args << ":" << iname << "\""; // No additional arguments + parse_args << arglist << ")) \n" + << tab8 << "return NULL;\n"; + + self_name = convert_self(f); + + /* Now slap the whole first part of the wrapper function together */ + + f.code << parse_args << get_pointers << check; + + + // Special handling for build values + + if (have_build) { + char temp1[256]; + char temp2[256]; + l->sub_parmnames(build); // Replace all parameter names + for (i = 0; i < l->nparms; i++) { + p = l->get(i); + if (strlen(p->name) > 0) { + sprintf(temp1,"_in_%s", p->name); + } else { + sprintf(temp1,"_in_arg%d", i); + } + sprintf(temp2,"_obj%d",i); + build.replaceid(temp1,temp2); + } + f.code << build; + } + + // This function emits code to call the real function. Assuming you read + // the parameters in correctly, this will work. + + call_name = ""; + call_name << self_name << name; + emit_func_call(call_name,d,l,f); + + // Now emit code to return the functions return value (if any). + // If there was a result, it was saved in _result. + // If the function is a void type, don't do anything. + + if ((tm = typemap_lookup("out","python",d,iname,"_result","_resultobj"))) { + // Yep. Use it instead of the default + f.code << tm << "\n"; + } else { + + if ((d->type != T_VOID) || (d->is_pointer)) { + // Now have return value, figure out what to do with it. + + if (!d->is_pointer) { + + // Function returns a "value" + + switch(d->type) { + + // Return an integer type + + case T_INT: case T_SINT: case T_UINT: case T_BOOL: + f.code << tab4 << "_resultobj = Py_BuildValue(\"i\",_result);\n"; + break; + case T_SHORT: case T_SSHORT: case T_USHORT: + f.code << tab4 << "_resultobj = Py_BuildValue(\"h\",_result);\n"; + break; + case T_LONG : case T_SLONG : case T_ULONG: + f.code << tab4 << "_resultobj = Py_BuildValue(\"l\",_result);\n"; + break; + case T_SCHAR: case T_UCHAR : + f.code << tab4 << "_resultobj = Py_BuildValue(\"b\",_result);\n"; + break; + + // Return a floating point value + + case T_DOUBLE : + f.code << tab4 << "_resultobj = Py_BuildValue(\"d\",_result);\n"; + break; + case T_FLOAT : + f.code << tab4 << "_resultobj = Py_BuildValue(\"f\",_result);\n"; + break; + + // Return a single ASCII value. Usually we need to convert + // it to a NULL-terminate string and return that instead. + + case T_CHAR : + f.code << tab4 << "_resultobj = Py_BuildValue(\"c\",_result);\n"; + break; + + case T_USER : + + // Return something by value + // We're living dangerously here, but life is short...play hard + + // Oops. Need another local variable + f.add_local("char","_ptemp[128]"); + + d->is_pointer++; + f.code << tab4 << "SWIG_MakePtr(_ptemp, (void *) _result,\"" + << d->print_mangle() << "\");\n"; + d->is_pointer--; + // Return a character string containing our pointer. + + f.code << tab4 << "_resultobj = Py_BuildValue(\"s\",_ptemp);\n"; + break; + default : + fprintf(stderr,"%s: Line %d. Unable to use return type %s in function %s.\n", input_file, line_number, d->print_type(), name); + break; + } + } else { + + // Return type is a pointer. We'll see if it's a char * and return + // a string. Otherwise, we'll convert it into a SWIG pointer and return + // that. + + if ((d->type == T_CHAR) && (d->is_pointer == 1)) { + + // Return a character string + f.code << tab4 << "_resultobj = Py_BuildValue(\"s\", _result);\n"; + + // If declared as a new object, free the result + + } else { + + // Build a SWIG pointer. + f.add_local("char","_ptemp[128]"); + f.code << tab4 << "if (_result) {\n" + << tab8 << "SWIG_MakePtr(_ptemp, (char *) _result,\"" + << d->print_mangle() << "\");\n"; + + // Return a character string containing our pointer. + f.code << tab8 << "_resultobj = Py_BuildValue(\"s\",_ptemp);\n"; + f.code << tab4 << "} else {\n" + << tab8 << "Py_INCREF(Py_None);\n" + << tab8 << "_resultobj = Py_None;\n" + << tab4 << "}\n"; + } + } + } else { + // no return value and no output args + //if (!have_output) { + f.code << tab4 << "Py_INCREF(Py_None);\n"; + f.code << tab4 << "_resultobj = Py_None;\n"; + //} + } + } + + // Check to see if there were any output arguments, if so we're going to + // create a Python list object out of the current result + + f.code << outarg; + + // If there was any other cleanup needed, do that + + f.code << cleanup; + + // Look to see if there is any newfree cleanup code + + if (NewObject) { + if ((tm = typemap_lookup("newfree","python",d,iname,"_result",""))) { + f.code << tm << "\n"; + } + } + + // See if there is any argument cleanup code + + if ((tm = typemap_lookup("ret","python",d,iname,"_result",""))) { + // Yep. Use it instead of the default + f.code << tm << "\n"; + } + + f.code << tab4 << "return _resultobj;\n"; + f.code << "}\n"; + + // Substitute the cleanup code + f.code.replace("$cleanup",cleanup); + + // Substitute the function name + f.code.replace("$name",iname); + + // Dump the function out + f.print(f_wrappers); + + // Now register the function with the interpreter. + + add_method(iname, wname); + + // Create a documentation entry for this + + if (doc_entry) { + static DocEntry *last_doc_entry = 0; + doc_entry->usage << usage; + if (last_doc_entry != doc_entry) { + doc_entry->cinfo << "returns " << d->print_type(); + last_doc_entry = doc_entry; + } + } + + // --------------------------------------------------------------------------- + // Create a shadow for this function (if enabled and not in a member function) + // --------------------------------------------------------------------------- + + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + String translate; + + int need_wrapper = 0; + int munge_return = 0; + int have_optional = 0; + + // Check return code for modification + if ((hash.lookup(d->name)) && (d->is_pointer <=1)) { + need_wrapper = 1; + munge_return = 1; + } + + if (docstring && doc_entry) + need_wrapper = 1; + + // If no modification is needed. We're just going to play some + // symbol table games instead + + if (!need_wrapper) { + func << iname << " = " << module << "." << iname << "\n\n"; + } else { + func << "def " << iname << "(*_args, **_kwargs):\n"; + + // Create a docstring for this + if (docstring && doc_entry) { + func << tab4 << "\"\"\"" << add_docstring(doc_entry) << "\"\"\"\n"; + } + + func << tab4 << "val = apply(" << module << "." << iname << ",_args,_kwargs)\n"; + + if (munge_return) { + // If the output of this object has been remapped in any way, we're + // going to return it as a bare object. + + if (!typemap_check("out",typemap_lang,d,iname)) { + + // If there are output arguments, we are going to return the value + // unchanged. Otherwise, emit some shadow class conversion code. + + if (!have_output) { + func << tab4 << "if val: val = " << (char *) hash.lookup(d->name) << "Ptr(val)"; + if (((hash.lookup(d->name)) && (d->is_pointer < 1)) || + ((hash.lookup(d->name)) && (d->is_pointer == 1) && NewObject)) + func << "; val.thisown = 1\n"; + else + func << "\n"; + } else { + // Does nothing--returns the value unmolested + } + } + } + func << tab4 << "return val\n\n"; + } + } +} + +// ----------------------------------------------------------------------- +// PYTHON::link_variable(char *name, char *iname, DataType *d) +// +// Input variables: +// name = the real name of the variable being linked +// iname = Name of the variable in the interpreter (may be different) +// d = Datatype of the variable. +// +// This creates a pair of functions for evaluating/setting the value +// of a variable. These are then added to the special SWIG global +// variable type. +// ----------------------------------------------------------------------- + +void PYTHON::link_variable(char *name, char *iname, DataType *t) { + + char *wname; + static int have_globals = 0; + char *tm; + + WrapperFunction getf, setf; + + // If this is our first call, add the globals variable to the + // Python dictionary. + + if (!have_globals) { + fprintf(f_init,"\t PyDict_SetItemString(d,\"%s\", SWIG_globals);\n",global_name); + have_globals=1; + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + vars << global_name << " = " << module << "." << global_name << "\n"; + } + } + // First make a sanitized version of the function name (in case it's some + // funky C++ thing). + + wname = name_wrapper(name,""); + + // --------------------------------------------------------------------- + // Create a function for setting the value of the variable + // --------------------------------------------------------------------- + + setf.def << "static int " << wname << "_set(PyObject *val) {"; + if (!(Status & STAT_READONLY)) { + if ((tm = typemap_lookup("varin","python",t,name,"val",name))) { + setf.code << tm << "\n"; + setf.code.replace("$name",iname); + } else { + if ((t->type != T_VOID) || (t->is_pointer)) { + if (!t->is_pointer) { + + // Have a real value here + + switch(t->type) { + case T_INT: case T_SHORT: case T_LONG : + case T_UINT: case T_USHORT: case T_ULONG: + case T_SINT: case T_SSHORT: case T_SLONG: + case T_SCHAR: case T_UCHAR: case T_BOOL: + // Get an integer value + setf.add_local(t->print_type(), "tval"); + setf.code << tab4 << "tval = " << t->print_cast() << "PyInt_AsLong(val);\n" + << tab4 << "if (PyErr_Occurred()) {\n" + << tab8 << "PyErr_SetString(PyExc_TypeError,\"C variable '" + << iname << "'(" << t->print_type() << ")\");\n" + << tab8 << "return 1; \n" + << tab4 << "}\n" + << tab4 << name << " = tval;\n"; + break; + + case T_FLOAT: case T_DOUBLE: + // Get a floating point value + setf.add_local(t->print_type(), "tval"); + setf.code << tab4 << "tval = " << t->print_cast() << "PyFloat_AsDouble(val);\n" + << tab4 << "if (PyErr_Occurred()) {\n" + << tab8 << "PyErr_SetString(PyExc_TypeError,\"C variable '" + << iname << "'(" << t->print_type() << ")\");\n" + << tab8 << "return 1; \n" + << tab4 << "}\n" + << tab4 << name << " = tval;\n"; + break; + + // A single ascii character + + case T_CHAR: + setf.add_local("char *", "tval"); + setf.code << tab4 << "tval = (char *) PyString_AsString(val);\n" + << tab4 << "if (PyErr_Occurred()) {\n" + << tab8 << "PyErr_SetString(PyExc_TypeError,\"C variable '" + << iname << "'(" << t->print_type() << ")\");\n" + << tab8 << "return 1; \n" + << tab4 << "}\n" + << tab4 << name << " = *tval;\n"; + break; + case T_USER: + t->is_pointer++; + setf.add_local(t->print_type(),"temp"); + get_pointer(iname,"value","val","temp",t,setf.code,"1"); + setf.code << tab4 << name << " = *temp;\n"; + t->is_pointer--; + break; + default: + fprintf(stderr,"%s : Line %d. Unable to link with type %s.\n", input_file, line_number, t->print_type()); + } + } else { + + // Parse a pointer value + + if ((t->type == T_CHAR) && (t->is_pointer == 1)) { + setf.add_local("char *", "tval"); + setf.code << tab4 << "tval = (char *) PyString_AsString(val);\n" + << tab4 << "if (PyErr_Occurred()) {\n" + << tab8 << "PyErr_SetString(PyExc_TypeError,\"C variable '" + << iname << "'(" << t->print_type() << ")\");\n" + << tab8 << "return 1; \n" + << tab4 << "}\n"; + + if (CPlusPlus) { + setf.code << tab4 << "if (" << name << ") delete [] " << name << ";\n" + << tab4 << name << " = new char[strlen(tval)+1];\n" + << tab4 << "strcpy((char *)" << name << ",tval);\n"; + } else { + setf.code << tab4 << "if (" << name << ") free(" << name << ");\n" + << tab4 << name << " = (char *) malloc(strlen(tval)+1);\n" + << tab4 << "strcpy((char *)" << name << ",tval);\n"; + } + } else { + + // Is a generic pointer value. + + setf.add_local(t->print_type(),"temp"); + get_pointer(iname,"value","val","temp",t,setf.code,"1"); + setf.code << tab4 << name << " = temp;\n"; + } + } + } + } + setf.code << tab4 << "return 0;\n"; + } else { + // Is a readonly variable. Issue an error + setf.code << tab4 << "PyErr_SetString(PyExc_TypeError,\"Variable " << iname + << " is read-only.\");\n" + << tab4 << "return 1;\n"; + } + + setf.code << "}\n"; + + // Dump out function for setting value + + setf.print(f_wrappers); + + // ---------------------------------------------------------------- + // Create a function for getting the value of a variable + // ---------------------------------------------------------------- + + getf.def << "static PyObject *" << wname << "_get() {"; + getf.add_local("PyObject *","pyobj"); + if ((tm = typemap_lookup("varout","python",t,name,name,"pyobj"))) { + getf.code << tm << "\n"; + getf.code.replace("$name",iname); + } else if ((tm = typemap_lookup("out","python",t,name,name,"pyobj"))) { + getf.code << tm << "\n"; + getf.code.replace("$name",iname); + } else { + if ((t->type != T_VOID) || (t->is_pointer)) { + if (!t->is_pointer) { + + /* Is a normal datatype */ + switch(t->type) { + case T_INT: case T_SINT: case T_UINT: + case T_SHORT: case T_SSHORT: case T_USHORT: + case T_LONG: case T_SLONG: case T_ULONG: + case T_SCHAR: case T_UCHAR: case T_BOOL: + getf.code << tab4 << "pyobj = PyInt_FromLong((long) " << name << ");\n"; + break; + case T_FLOAT: case T_DOUBLE: + getf.code << tab4 << "pyobj = PyFloat_FromDouble((double) " << name << ");\n"; + break; + case T_CHAR: + getf.add_local("char","ptemp[2]"); + getf.code << tab4 << "ptemp[0] = " << name << ";\n" + << tab4 << "ptemp[1] = 0;\n" + << tab4 << "pyobj = PyString_FromString(ptemp);\n"; + break; + case T_USER: + // Hack this into a pointer + getf.add_local("char", "ptemp[128]"); + t->is_pointer++; + getf.code << tab4 << "SWIG_MakePtr(ptemp,(char *) &" << name + << "," << quote << t->print_mangle() << quote << ");\n" + << tab4 << "pyobj = PyString_FromString(ptemp);\n"; + t->is_pointer--; + break; + default: + fprintf(stderr,"Unable to link with type %s\n", t->print_type()); + break; + } + } else { + + // Is some sort of pointer value + if ((t->type == T_CHAR) && (t->is_pointer == 1)) { + getf.code << tab4 << "if (" << name << ")\n" + << tab8 << "pyobj = PyString_FromString(" << name << ");\n" + << tab4 << "else pyobj = PyString_FromString(\"(NULL)\");\n"; + } else { + getf.add_local("char","ptemp[128]"); + getf.code << tab4 << "SWIG_MakePtr(ptemp, (char *) " << name << ",\"" + << t->print_mangle() << "\");\n" + << tab4 << "pyobj = PyString_FromString(ptemp);\n"; + } + } + } + } + + getf.code << tab4 << "return pyobj;\n" + << "}\n"; + + getf.print(f_wrappers); + + // Now add this to the variable linking mechanism + + fprintf(f_init,"\t SWIG_addvarlink(SWIG_globals,\"%s\",%s_get, %s_set);\n", iname, wname, wname); + + + // Fill in the documentation entry + + if (doc_entry) { + doc_entry->usage << usage_var(iname, t); + doc_entry->cinfo << "Global : " << t->print_type() << " " << name; + } + + // ---------------------------------------------------------- + // Output a shadow variable. (If applicable and possible) + // ---------------------------------------------------------- + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + if ((hash.lookup(t->name)) && (t->is_pointer <= 1)) { + vars << iname << " = " << (char *) hash.lookup(t->name) << "Ptr(" << module << "." << global_name + << "." << iname << ")\n"; + } + } +} + +// ----------------------------------------------------------------------- +// PYTHON::declare_const(char *name, char *iname, DataType *type, char *value) +// +// Makes a constant as defined with #define. Constants are added to the +// module's dictionary and are **NOT** guaranteed to be read-only, +// sorry. +// +// ------------------------------------------------------------------------ + +void PYTHON::declare_const(char *name, char *, DataType *type, char *value) { + + char *tm; + + // Make a static python object + + if ((tm = typemap_lookup("const","python",type,name,value,name))) { + fprintf(f_init,"%s\n",tm); + } else { + + if ((type->type == T_USER) && (!type->is_pointer)) { + fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number); + return; + } + + if (type->is_pointer == 0) { + switch(type->type) { + case T_INT:case T_SINT: case T_UINT: case T_BOOL: + case T_SHORT: case T_SSHORT: case T_USHORT: + case T_LONG: case T_SLONG: case T_ULONG: + case T_SCHAR: case T_UCHAR: + fprintf(f_init,"\t PyDict_SetItemString(d,\"%s\", PyInt_FromLong((long) %s));\n",name,value); + break; + case T_DOUBLE: + case T_FLOAT: + fprintf(f_init,"\t PyDict_SetItemString(d,\"%s\", PyFloat_FromDouble((double) %s));\n",name,value); + break; + case T_CHAR : + fprintf(f_init,"\t PyDict_SetItemString(d,\"%s\", PyString_FromString(\"%s\"));\n",name,value); + break; + default: + fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number); + break; + } + } else { + if ((type->type == T_CHAR) && (type->is_pointer == 1)) { + fprintf(f_init,"\t PyDict_SetItemString(d,\"%s\", PyString_FromString(\"%s\"));\n",name,value); + } else { + // A funky user-defined type. We're going to munge it into a string pointer value + fprintf(f_init,"\t {\n"); + fprintf(f_init,"\t\t char %s_char[%d];\n", name, (int) strlen(type->print_mangle()) + 20); + fprintf(f_init,"\t\t SWIG_MakePtr(%s_char, (void *) (%s),\"%s\");\n", + name, value, type->print_mangle()); + fprintf(f_init,"\t\t PyDict_SetItemString(d,\"%s\", PyString_FromString(%s_char));\n",name,name); + fprintf(f_init,"\t }\n"); + } + } + } + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + vars << name << " = " << module << "." << name << "\n"; + } + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << usage_const(name,type,value); + doc_entry->cinfo = ""; + doc_entry->cinfo << "Constant: " << type->print_type(); + } +} + +// ---------------------------------------------------------------------- +// PYTHON::usage_var(char *iname, DataType *t) +// +// This function produces a string indicating how to use a variable. +// It is called by the documentation system to produce syntactically +// correct documentation entires. +// +// s is a pointer to a character pointer. You should create +// a string and set this pointer to point to it. +// ---------------------------------------------------------------------- + +char *PYTHON::usage_var(char *iname, DataType *) { + + static String temp; + + temp = ""; + temp << global_name << "." << iname; + + // Create result. Don't modify this + + return temp.get(); +} + +// --------------------------------------------------------------------------- +// PYTHON::usage_func(char *iname, DataType *t, ParmList *l) +// +// Produces a string indicating how to call a function in the target +// language. +// +// --------------------------------------------------------------------------- + +char *PYTHON::usage_func(char *iname, DataType *, ParmList *l) { + + static String temp; + Parm *p; + int i; + + temp = ""; + temp << iname << "("; + + // Now go through and print parameters + // You probably don't need to change this + + i = 0; + p = l->get_first(); + while (p != 0) { + if (!p->ignore) { + i++; + /* If parameter has been named, use that. Otherwise, just print a type */ + + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + if (strlen(p->name) > 0) { + temp << p->name; + } else { + temp << p->t->print_type(); + } + } + p = l->get_next(); + if (p != 0) { + if (!p->ignore) + temp << ","; + } + } else { + p = l->get_next(); + if (p) { + if ((!p->ignore) && (i > 0)) + temp << ","; + } + } + } + + temp << ")"; + + // Create result. Don't change this + + return temp.get(); + +} + + +// ---------------------------------------------------------------------- +// PYTHON::usage_const(char *iname, DataType *type, char *value) +// +// Produces a string for a constant. Really about the same as +// usage_var() except we'll indicate the value of the constant. +// ---------------------------------------------------------------------- + +char *PYTHON::usage_const(char *iname, DataType *, char *value) { + + static String temp; + temp = ""; + temp << iname << " = " << value; + + return temp.get(); +} + +// ----------------------------------------------------------------------- +// PYTHON::add_native(char *name, char *funcname) +// +// Add a native module name to the methods list. +// ----------------------------------------------------------------------- + +void PYTHON::add_native(char *name, char *funcname) { + add_method(name, funcname); + if (shadow) { + func << name << " = " << module << "." << name << "\n\n"; + } +} + +// ----------------------------------------------------------------------- +// PYTHON::cpp_class_decl(char *name, char *rename, char *type) +// +// Treatment of an empty class definition. Used to handle +// shadow classes across modules. +// ----------------------------------------------------------------------- + +void PYTHON::cpp_class_decl(char *name, char *rename, char *type) { + char temp[256]; + if (shadow) { + hash.add(name,copy_string(rename)); + // Add full name of datatype to the hash table + if (strlen(type) > 0) { + sprintf(temp,"%s %s", type, name); + hash.add(temp,copy_string(rename)); + } + } +} + +// ----------------------------------------------------------------------- +// PYTHON::pragma(char *name, char *type) +// +// Pragma directive. Used to do various python specific things +// ----------------------------------------------------------------------- + +void PYTHON::pragma(char *lang, char *cmd, char *value) { + + if (strcmp(lang,"python") == 0) { + if (strcmp(cmd,"CODE") == 0) { + if (shadow) { + fprintf(f_shadow,"%s\n",value); + } + } else if (strcmp(cmd,"code") == 0) { + if (shadow) { + fprintf(f_shadow,"%s\n",value); + } + } else if (strcmp(cmd,"include") == 0) { + if (shadow) { + if (value) { + if (get_file(value,pragma_include) == -1) { + fprintf(stderr,"%s : Line %d. Unable to locate file %s\n", input_file, line_number, value); + } + } + } + } else { + fprintf(stderr,"%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + } +} + + +struct PyPragma { + PyPragma(char *method, char *text) : m_method(method), m_text(text), next(0) { } + ~PyPragma() { if (next) delete next; } + String m_method; + String m_text; + PyPragma *next; +}; + +static PyPragma *pragmas = 0; + +// ----------------------------------------------------------------------------- +// PYTHON::cpp_pragma(Pragma *plist) +// +// Handle C++ pragmas +// ----------------------------------------------------------------------------- + +void PYTHON::cpp_pragma(Pragma *plist) { + PyPragma *pyp1 = 0, *pyp2 = 0; + if (pragmas) { + delete pragmas; + pragmas = 0; + } + while (plist) { + if (strcmp(plist->lang,"python") == 0) { + if (strcmp(plist->name,"addtomethod") == 0) { + // parse value, expected to be in the form "methodName:line" + String temp = plist->value; + char* txtptr = strchr(temp.get(), ':'); + if (txtptr) { + // add name and line to a list in current_class + *txtptr = 0; + txtptr++; + pyp1 = new PyPragma(temp,txtptr); + if (pyp2) { + pyp2->next = pyp1; + pyp2 = pyp1; + } else { + pragmas = pyp1; + pyp2 = pragmas; + } + } else { + fprintf(stderr,"%s : Line %d. Malformed addtomethod pragma. Should be \"methodName:text\"\n", + plist->filename.get(),plist->lineno); + } + } else if (strcmp(plist->name, "addtoclass") == 0) { + pyp1 = new PyPragma("__class__",plist->value); + if (pyp2) { + pyp2->next = pyp1; + pyp2 = pyp1; + } else { + pragmas = pyp1; + pyp2 = pragmas; + } + } + } + plist = plist->next; + } +} + +// -------------------------------------------------------------------------------- +// PYTHON::emitAddPragmas(String& output, char* name, char* spacing); +// +// Search the current class pragma for any text belonging to name. +// Append the text properly spaced to the output string. +// -------------------------------------------------------------------------------- + +void PYTHON::emitAddPragmas(String& output, char* name, char* spacing) +{ + PyPragma *p = pragmas; + while (p) { + if (strcmp(p->m_method,name) == 0) { + output << spacing << p->m_text << "\n"; + } + p = p->next; + } +} diff --git a/SWIG/Source/Modules1.1/python.h b/SWIG/Source/Modules1.1/python.h new file mode 100644 index 000000000..eb7da3011 --- /dev/null +++ b/SWIG/Source/Modules1.1/python.h @@ -0,0 +1,111 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/************************************************************************** + * $Header$ + * + * python.h + * + * Header file for Python module. Warning ; this is work in progress. + **************************************************************************/ + +class PYTHON : public Language { +protected: + char *module; // Module name + char *path; // Pathname of where to look for library files + char *methods; // Method table name + char *global_name; // Name of global variables. + void get_pointer(char *iname, char *srcname, char *src, char *dest, DataType *t, String &f, char *ret); + int shadow; + int have_defarg; + int docstring; + int have_output; + int use_kw; + FILE *f_shadow; + struct Method { // Methods list. Needed to build methods + char *name; // Array at very end. + char *function; + Method *next; + }; + Method *head; + Hash hash; + String classes; + String func; + String vars; + String modinit; + String modextern; + + char *import_file; + void add_method(char *name, char *function); + void print_methods(); + char *usage_var(char *, DataType *); + char *usage_func(char *, DataType *, ParmList *); + char *usage_const(char *, DataType *, char *); + char *add_docstring(DocEntry *de); + + // Add for Python-COM support + virtual void initialize_cmodule(); + virtual void close_cmodule(); + virtual void emit_function_header(WrapperFunction &emit_to, char *wname); + virtual char *convert_self(WrapperFunction &f); + virtual char *make_funcname_wrapper(char *fnName); + void emitAddPragmas(String& output, char* name, char* spacing); +public : + PYTHON() { + module = (char *) 0; + path = "python"; // Set this to subdirectory where language + // Dependent library files will be stored + head = 0; // Head of method list + global_name = "cvar"; + shadow = 0; + have_defarg = 0; + import_file = 0; + use_kw = 0; + }; + + // Don't change any of this + void parse_args(int, char *argv[]); + void parse(); + void create_function(char *, char *, DataType *, ParmList *); + void link_variable(char *, char *, DataType *); + void declare_const(char *, char *, DataType *, char *); + void initialize(void); + void headers(void); + void close(void); + void set_module(char *, char **); + void set_init(char *); + void add_native(char *, char *); + void create_command(char *, char *); + void import(char *); + + // C++ extensions---for creating shadow classes + + void cpp_member_func(char *name, char *iname, DataType *t, ParmList *l); + void cpp_constructor(char *name, char *iname, ParmList *l); + void cpp_destructor(char *name, char *newname); + void cpp_open_class(char *classname, char *rname, char *ctype, int strip); + void cpp_close_class(); + void cpp_cleanup(); + void cpp_inherit(char **baseclass, int mode = INHERIT_ALL); + void cpp_variable(char *name, char *iname, DataType *t); + void cpp_declare_const(char *name, char *iname, DataType *type, char *value); + void cpp_class_decl(char *, char *,char *); + void pragma(char *, char *, char *); + void cpp_pragma(Pragma *); + void add_typedef(DataType *t, char *name); +}; + +#define PYSHADOW_MEMBER 0x2 + diff --git a/SWIG/Source/Modules1.1/swigmain.cxx b/SWIG/Source/Modules1.1/swigmain.cxx new file mode 100644 index 000000000..8f6ecc087 --- /dev/null +++ b/SWIG/Source/Modules1.1/swigmain.cxx @@ -0,0 +1,166 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * swigmain.cxx + * + * The main program. + * + ***********************************************************************/ + +#include "wrap.h" +#include "tcl8.h" +#include "perl5.h" +#include "python.h" +#include "guile.h" +#include "debug.h" +#include "ascii.h" +#include "latex.h" +#include "html.h" +#include "nodoc.h" +#include + +static char *usage = "\ +swig filename\n\n\ +Target Language Options:\n\ + -tcl - Generate Tcl wrappers.\n\ + -python - Generate Python wrappers.\n\ + -perl5 - Generate Perl5 wrappers.\n\ + -guile - Generate Guile wrappers.\n\ + -debug - Parser debugging module.\n"; + +#ifdef MACSWIG +static char *macmessage = "\ +Copyright (c) 1995-1997\n\ +University of Utah and the Regents of the University of California\n\n\ +Enter SWIG processing options and filename below. For example :\n\ +\n\ + -tcl -c++ interface.i\n\ +\n\ +-help displays a list of all available options.\n\ +\n\ +Note : Macintosh filenames should be enclosed in quotes if they contain whitespace.\n\ +\n"; + +#endif + +//----------------------------------------------------------------- +// main() +// +// Main program. Initializes the files and starts the parser. +//----------------------------------------------------------------- + +#ifndef MACSWIG +int main(int argc, char **argv) { +#else +int Mac_main(int argc, char **argv) { +#endif + + int i; + + Language *dl = new SWIG_LANG; + Documentation *dd = new SWIG_DOC; + extern int SWIG_main(int, char **, Language *, Documentation *); + + init_args(argc,argv); + + // Get options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if(strcmp(argv[i],"-tcl") == 0) { + fprintf(stderr,"swig: -tcl option now implies -tcl8\n"); + dl = new TCL8; + mark_arg(i); + } else if (strcmp(argv[i],"-tcl8") == 0) { + dl = new TCL8; + mark_arg(i); + } else if (strcmp(argv[i],"-perl5") == 0) { + dl = new PERL5; + mark_arg(i); + } else if (strcmp(argv[i],"-python") == 0) { + dl = new PYTHON; + mark_arg(i); + } else if (strcmp(argv[i],"-debug") == 0) { + dl = new DEBUGLANG; + mark_arg(i); + } else if (strcmp(argv[i],"-guile") == 0) { + dl = new GUILE; + mark_arg(i); + } else if (strcmp(argv[i],"-help") == 0) { + fputs(usage,stderr); + mark_arg(i); + } + } + } + SWIG_main(argc,argv,dl,dd); + return 0; +} + +#ifdef MACSWIG +int MacMainEntry(char *options) { + static char *_argv[256]; + int i,argc; + char *c,*s,*t; + + swig_log = fopen("swig_log","w"); + fprintf(swig_log,"SWIG 1.1\n"); + fprintf(swig_log,"Options : %s\n", options); + fprintf(swig_log,"-----------------------------------------------------\n"); + + // Tokenize the user input + + _argv[0] = "swig"; + i=1; + c = options; + while (*c) { + while(isspace(*c)) c++; + if (*c) { + s = c; // Starting character + while(isgraph(*c)) { + if (*c == '\"') { + c++; + while ((*c) && (*c != '\"')) + c++; + c++; + } else { + c++; + } + } + // Found some whitespace + if (*c) { + *c = 0; + c++; + } + _argv[i] = copy_string(s); + // Go through and remove quotes (if necessary) + + t = _argv[i]; + while(*s) { + if (*s != '\"') + *(t++) = *s; + s++; + } + *t = 0; + i++; + } + } + argc = i; + _argv[i] = 0; + return Mac_main(argc,_argv); +} + +#endif diff --git a/SWIG/Source/Modules1.1/tcl8.cxx b/SWIG/Source/Modules1.1/tcl8.cxx new file mode 100644 index 000000000..4280af008 --- /dev/null +++ b/SWIG/Source/Modules1.1/tcl8.cxx @@ -0,0 +1,1552 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * tcl8.cxx + * + * Module for creating Tcl 8.0 native wrapper functions. + ***********************************************************************/ + +#include "swig.h" +#include "tcl8.h" +#include + +static char *Tcl_config="swigtcl.swg"; +static char *usage = "\ +Tcl 8.0 Options (available with -tcl)\n\ + -module name - Set name of module\n\ + -prefix name - Set a prefix to be appended to all names\n\ + -namespace - Build module into a Tcl 8 namespace. \n\ + -noobject - Omit code for object oriented interface.\n\ + -old - Use old SWIG interface (same as -noobject).\n\n"; + +static char *ns_name = 0; + +static String mod_init; +static String mod_extern; +static String cmd_info; +static String var_info; + +// --------------------------------------------------------------------- +// TCL8::parse_args(int argc, char *argv[]) +// +// Parse tcl specific command line options +// --------------------------------------------------------------------- + +void TCL8::parse_args(int argc, char *argv[]) { + + int i = 1; + sprintf(LibDir,"%s",tcl_path); + + // Look for certain command line options + + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-prefix") == 0) { + if (argv[i+1]) { + prefix = new char[strlen(argv[i+1])+2]; + strcpy(prefix, argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-module") == 0) { + if (argv[i+1]) { + set_module(argv[i+1],0); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-namespace") == 0) { + nspace = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-old") == 0) { + shadow = 0; + mark_arg(i); + } else if (strcmp(argv[i],"-noobject") == 0) { + shadow = 0; + mark_arg(i); + } else if (strcmp(argv[i],"-help") == 0) { + fputs(usage,stderr); + } + } + } + + // If a package has been specified, make sure it ends with a '_' + + if (prefix) { + ns_name = copy_string(prefix); + if (prefix[strlen(prefix)] != '_') { + prefix[strlen(prefix)+1] = 0; + prefix[strlen(prefix)] = '_'; + } + } else + prefix = ""; + + // Create a symbol SWIGTCL + + add_symbol("SWIGTCL",0,0); + add_symbol("SWIGTCL8",0,0); + + // Set name of typemaps + + typemap_lang = "tcl8"; + +} + +// --------------------------------------------------------------------- +// void TCL8::parse() +// +// Start parsing an interface file for Tcl. +// --------------------------------------------------------------------- + +void TCL8::parse() { + + fprintf(stderr,"Making wrappers for Tcl 8.x\n"); + + // Print out TCL specific headers + + headers(); + + // Run the parser + + yyparse(); + +} + +// --------------------------------------------------------------------- +// TCL8::set_module(char *mod_name,char **mod_list) +// +// Sets the module name. +// Does nothing if it's already set (so it can be overridden as a command +// line option). +// +// mod_list is a NULL-terminated list of additional modules. This +// is really only useful when building static executables and other +// things. +//---------------------------------------------------------------------- + +void TCL8::set_module(char *mod_name, char **mod_list) { + + char temp[256], *c; + int i; + + if (module) return; + + module = new char[strlen(mod_name)+1]; + strcpy(module,mod_name); + + // Fix capitalization for Tcl + + c = module; + while (*c) { + *c = (char) tolower(*c); + c++; + } + + // Now create an initialization function + + sprintf(temp,"%s_Init", module); + init_name = new char[strlen(temp) + 1]; + strcpy(init_name, temp); + *init_name = toupper(*init_name); + + if (!ns_name) ns_name = copy_string(module); + + // If namespaces have been specified, set the prefix to the module name + + if ((nspace) && (strlen(prefix) < 1)) { + prefix = new char[strlen(module)+2]; + strcpy(prefix,module); + prefix[strlen(module)] = '_'; + prefix[strlen(module)+1] = 0; + } + + // If additional modules have been specified, create some code for + // initializing them. + + if (mod_list) { + i = 0; + while (mod_list[i]) { + c = mod_list[i]; + while (*c) { + *c = (char) tolower(*c); + c++; + } + sprintf(temp,"%s_Init",mod_list[i]); + temp[0] = toupper(temp[0]); + + // Dump out some initialization code + + mod_init << tab4 << "if (" << temp << "(" << interp_name << ") == TCL_ERROR) {\n" + << tab8 << "return TCL_ERROR;\n" + << tab4 << "}\n\n"; + mod_extern << "extern int " << temp << "(Tcl_Interp *);\n"; + i++; + } + } +} + + +// --------------------------------------------------------------------- +// TCL8::set_init(char *iname) +// +// Sets the initialization function name. +// Does nothing if it's already set +// +//---------------------------------------------------------------------- + +void TCL8::set_init(char *iname) { + + if (init_name) return; + init_name = new char[strlen(iname)+1]; + strcpy(init_name, iname); + +} + +// --------------------------------------------------------------------- +// TCL8::headers(void) +// +// Generate the appropriate header files for TCL interface. +// ---------------------------------------------------------------------- + +void TCL8::headers(void) +{ + + emit_banner(f_runtime); + + // Include a Tcl configuration file for Unix,Mac,Wintel. + + if (NoInclude) { + fprintf(f_runtime,"#define SWIG_NOINCLUDE\n"); + } + + if (insert_file("swigtcl8.swg",f_runtime) == -1) { + fprintf(stderr,"SWIG : Fatal error. Unable to locate 'swigtcl8.swg' in SWIG library.\n"); + SWIG_exit(1); + } +} + +// -------------------------------------------------------------------- +// TCL8::initialize(void) +// +// Produces an initialization function. Assumes that the init function +// name has already been specified. +// --------------------------------------------------------------------- + +void TCL8::initialize() +{ + + if ((!ns_name) && (nspace)) { + fprintf(stderr,"Tcl error. Must specify a namespace.\n"); + SWIG_exit(1); + } + + if (!init_name) { + init_name = "Swig_Init"; + fprintf(stderr,"SWIG : *** Warning. No module name specified.\n"); + } + + fprintf(f_header,"#define SWIG_init %s\n", init_name); + if (!module) module = "swig"; + fprintf(f_header,"#define SWIG_name \"%s\"\n", module); + if (nspace) { + fprintf(f_header,"#define SWIG_prefix \"%s::\"\n", ns_name); + fprintf(f_header,"#define SWIG_namespace \"%s\"\n\n", ns_name); + } else { + fprintf(f_header,"#define SWIG_prefix \"%s\"\n", prefix); + fprintf(f_header,"#define SWIG_namespace \"\"\n\n"); + } + fprintf(f_header,"#ifdef __cplusplus\n"); + fprintf(f_header,"extern \"C\" {\n"); + fprintf(f_header,"#endif\n"); + fprintf(f_header,"#ifdef MAC_TCL\n"); + fprintf(f_header,"#pragma export on\n"); + fprintf(f_header,"#endif\n"); + fprintf(f_header,"SWIGEXPORT(int) %s(Tcl_Interp *);\n", init_name); + fprintf(f_header,"#ifdef MAC_TCL\n"); + fprintf(f_header,"#pragma export off\n"); + fprintf(f_header,"#endif\n"); + fprintf(f_header,"#ifdef __cplusplus\n"); + fprintf(f_header,"}\n"); + fprintf(f_header,"#endif\n"); + + + fprintf(f_init,"SWIGEXPORT(int) %s(Tcl_Interp *%s) {\n", init_name, interp_name); + fprintf(f_init,"\t int i;\n"); + if (nspace) { + fprintf(f_init,"#ifdef ITCL_NAMESPACES\n"); + fprintf(f_init,"\t Itcl_Namespace spaceId;\n"); + fprintf(f_init,"#endif\n"); + } + + fprintf(f_init,"\t if (%s == 0) \n", interp_name); + fprintf(f_init,"\t\t return TCL_ERROR;\n"); + + /* Check to see if other initializations need to be performed */ + + if (strlen(mod_extern.get())) { + fprintf(f_init,"%s\n",mod_init.get()); + fprintf(f_header,"#ifdef __cplusplus\n"); + fprintf(f_header,"extern \"C\" {\n"); + fprintf(f_header,"#endif\n"); + fprintf(f_header,"%s\n",mod_extern.get()); + fprintf(f_header,"#ifdef __cplusplus\n"); + fprintf(f_header,"}\n"); + fprintf(f_header,"#endif\n"); + } + + + /* Check to see if we're adding support for Tcl8 nspaces */ + if (nspace) { + fprintf(f_init,"#if (TCL_MAJOR_VERSION >= 8)\n"); + fprintf(f_init,"\t Tcl_Eval(%s,\"namespace eval %s { }\");\n", interp_name, ns_name); + fprintf(f_init,"#endif\n"); + } + + cmd_info << "\nstatic _swig_command_info _swig_commands[] = {\n"; + var_info << "\nstatic _swig_var_info _swig_variables[] = {\n"; +} + +// --------------------------------------------------------------------- +// TCL8::close(void) +// +// Wrap things up. Close initialization function. +// --------------------------------------------------------------------- + +void TCL8::close(void) +{ + extern void emit_type_table(); + cmd_info << tab4 << "{0, 0, 0}\n" + << "};\n"; + + var_info << tab4 << "{0,0,0,0}\n" + << "};\n"; + + fprintf(f_wrappers,"%s", cmd_info.get()); + fprintf(f_wrappers,"%s", var_info.get()); + + fprintf(f_init,"\tfor (i = 0; _swig_commands[i].name; i++) {\n"); + fprintf(f_init,"\t Tcl_CreateObjCommand(interp, (char *) _swig_commands[i].name, _swig_commands[i].wrapper, _swig_commands[i].clientdata, NULL);\n"); + fprintf(f_init,"\t}\n"); + + fprintf(f_init,"\tfor (i = 0; _swig_variables[i].name; i++) {\n"); + fprintf(f_init,"\t Tcl_SetVar(interp, (char *) _swig_variables[i].name, \"\", TCL_GLOBAL_ONLY);\n"); + fprintf(f_init,"\t Tcl_TraceVar(interp, (char *) _swig_variables[i].name, TCL_TRACE_READS | TCL_GLOBAL_ONLY, _swig_variables[i].get, (ClientData) _swig_variables[i].addr);\n"); + fprintf(f_init,"\t Tcl_TraceVar(interp, (char *) _swig_variables[i].name, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, _swig_variables[i].set, (ClientData) _swig_variables[i].addr);\n"); + fprintf(f_init,"\t}\n"); + + // Dump the pointer equivalency table + + emit_type_table(); + + // emit_ptr_equivalence(f_init); + + // Close the init file and quit + + fprintf(f_init,"%s",postinit.get()); + fprintf(f_init,"\t return TCL_OK;\n"); + fprintf(f_init,"}\n"); + +} + +// ---------------------------------------------------------------------- +// TCL8::get_pointer(char *iname, char *srcname, char *src, char *dest, +// DataType *t, String &f, char *ret) +// +// iname = name of function or variable +// srcname = name of source +// src = source variable in wrapper code +// dest = destination variable in wrapper code +// t = Datatype +// f = String where output is going to go +// ret = Return action +// ---------------------------------------------------------------------- + +void TCL8::get_pointer(char *iname, char *srcname, char *src, char *dest, + DataType *t, String &f, char *ret) { + + // Pointers are read as hex-strings with encoded type information + + t->remember(); + f << tab4 << "if ((SWIG_ConvertPtr(interp," << src << ",(void **) &" << dest << ","; + + if (t->type == T_VOID) f << "0)) == TCL_ERROR) { return TCL_ERROR; }\n"; + else + f << "SWIGTYPE" << t->print_mangle() << ")) == TCL_ERROR) { return TCL_ERROR; }\n"; + + // Now emit code according to the level of strictness desired +#ifdef OLD + switch(TypeStrict) { + case 0: // No type checking + f << tab4 << "}\n"; + break; + case 1: // Warning message only + f << tab8 << "fprintf(stderr,\"Warning : type mismatch in " << srcname + << " of " << iname << ". Expected " << t->print_mangle() + << ", received %s\\n\", rettype);\n" + << tab4 << "}\n"; + case 2: // Super strict mode. + f << tab8 << "Tcl_SetResult(interp, \"Type error in " << srcname << " of " << iname + << ". Expected " << t->print_mangle() << ", received \", TCL_STATIC);\n" + << tab8 << "Tcl_AppendElement(interp, rettype);\n" + << tab8 << ret << ";\n" + << tab4 << "}\n"; + break; + default : + fprintf(stderr,"Unknown strictness level\n"); + break; + } +#endif +} + + +// ---------------------------------------------------------------------- +// TCL8::create_command(char *cname, char *iname) +// +// Creates a Tcl command from a C function. +// ---------------------------------------------------------------------- + +void TCL8::create_command(char *cname, char *iname) { + + char *wname = name_wrapper(cname,prefix); + + cmd_info << tab4 << "{ SWIG_prefix \"" << iname << "\", " << wname << ", NULL},\n"; + + // Add interpreter name to repeatcmd hash table. This hash is used in C++ code + // generation to try and find repeated wrapper functions. + + repeatcmd.add(iname,copy_string(wname)); +} + +// ---------------------------------------------------------------------- +// TCL8::create_function(char *name, char *iname, DataType *d, ParmList *l) +// +// Create a function declaration and register it with the interpreter. +// ---------------------------------------------------------------------- + +void TCL8::create_function(char *name, char *iname, DataType *d, ParmList *l) +{ + Parm *p; + int pcount,i,j; + char *wname; + char *usage = 0, *tm; + char source[64]; + char target[64]; + char argnum[32]; + WrapperFunction f; + String incode, cleanup, outarg, build; + int numopt= 0; + int have_build = 0; + String argstr; + String args; + + // Make a wrapper name for this function + + wname = name_wrapper(iname,prefix); + + // Now write the wrapper function itself....this is pretty ugly + + f.def << "static int " << wname << "(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {"; + + // Print out variables for storing arguments. + + pcount = emit_args(d, l, f); + numopt = l->numopt(); + + // Create a local variable for holding the interpreter result value + + // f.add_local("Tcl_Obj *", "tcl_result"); + + // Check the number of arguments + + usage = usage_func(iname,d,l); // Create a usage string + + // + // f.code << tab4 << "if ((objc < " << (pcount-numopt) +1 << ") || (objc > " << l->numarg()+1 << ")) {\n" + // << tab8 << "Tcl_SetResult(interp, \"Wrong # args. " << usage << "\", TCL_STATIC);\n" + // << tab8 << "return TCL_ERROR;\n" + // << tab4 << "}\n"; + + argstr = "\""; + args = ""; + + // Extract parameters. This case statement should be used to extract + // Function parameters. Add more cases if you want to do more. + + i = 0; + j = 0; + p = l->get_first(); + while (p != 0) { + // Produce string representations of the source and target arguments + sprintf(source,"objv[%d]",j+1); + sprintf(target,"_arg%d",i); + sprintf(argnum,"%d",j+1); + + // See if this argument is being ignored + + if (!p->ignore) { + if (j == (pcount-numopt)) + argstr << "|"; + // f.code << tab4 << "if (objc >" << j+1 << ") { \n"; + + if ((tm = typemap_lookup("in","tcl8",p->t,p->name,source,target,&f))) { + argstr << "o"; + args << ",0"; + + // Yep. Use it instead of the default + incode << tm << "\n"; + incode.replace("$argnum",argnum); + incode.replace("$arg",source); + } else { + if (!p->t->is_pointer) { + + // Extract a parameter by value. + + switch(p->t->type) { + + // Signed Integers + + case T_BOOL: + case T_INT: + case T_SINT: + case T_UINT: + argstr << "i"; + args << ",&" << target; + break; + case T_SHORT: + case T_SSHORT: + case T_USHORT: + argstr << "h"; + args << ",&" << target; + break; + case T_LONG: + case T_SLONG: + case T_ULONG: + argstr << "l"; + args << ",&" << target; + break; + case T_SCHAR: + case T_UCHAR: + argstr << "b"; + args << ",&" << target; + break; + + // Floating point + + case T_FLOAT: + argstr << "f"; + args << ",&" << target; + break; + + case T_DOUBLE: + argstr << "d"; + args << ",&" << target; + break; + + // A single character + case T_CHAR : + argstr << "c"; + args << ",&" << target; + break; + + // Void.. Do nothing. + + case T_VOID : + break; + // User defined. This is an error. + + case T_USER: + // Unsupported data type + + default : + fprintf(stderr,"%s : Line %d: Unable to use type %s as a function argument.\n", + input_file, line_number, p->t->print_type()); + break; + } + } else { + + // Function argument is some sort of pointer + // Look for a string. Otherwise, just pull off a pointer. + + if ((p->t->type == T_CHAR) && (p->t->is_pointer == 1)) { + argstr << "s"; + args << ",&" << target; + } else { + p->t->remember(); + argstr << "p"; + args << ",&" << target << ", SWIGTYPE" << p->t->print_mangle(); + } + } + } + j++; + } + + // Check to see if there is any sort of "build" typemap (highly complicated) + + if ((tm = typemap_lookup("build","tcl8",p->t,p->name,source,target))) { + build << tm << "\n"; + have_build = 1; + } + + // Check to see if there was any sort of a constaint typemap + if ((tm = typemap_lookup("check","tcl8",p->t,p->name,source,target))) { + // Yep. Use it instead of the default + incode << tm << "\n"; + incode.replace("$argnum",argnum); + incode.replace("$arg",source); + } + + // Check if there was any cleanup code (save it for later) + if ((tm = typemap_lookup("freearg","tcl8",p->t,p->name,target,"tcl_result"))) { + // Yep. Use it instead of the default + cleanup << tm << "\n"; + cleanup.replace("$argnum",argnum); + cleanup.replace("$arg",source); + } + // Look for output arguments + if ((tm = typemap_lookup("argout","tcl8",p->t,p->name,target,"tcl_result"))) { + outarg << tm << "\n"; + outarg.replace("$argnum",argnum); + outarg.replace("$arg",source); + } + i++; + p = l->get_next(); // Get next parameter and continue + } + + argstr << ":" << usage << "\""; + f.code << tab4 << "if (SWIG_GetArgs(interp, objc, objv," << argstr << args << ") == TCL_ERROR) return TCL_ERROR;\n"; + + f.code << incode; + + // If there was a "build" typemap, we need to go in and perform a serious hack + + if (have_build) { + char temp1[32]; + char temp2[256]; + l->sub_parmnames(build); // Replace all parameter names + j = 1; + for (i = 0; i < l->nparms; i++) { + p = l->get(i); + if (strlen(p->name) > 0) { + sprintf(temp1,"_in_%s", p->name); + } else { + sprintf(temp1,"_in_arg%d", i); + } + sprintf(temp2,"argv[%d]",j); + build.replaceid(temp1,temp2); + if (!p->ignore) + j++; + } + f.code << build; + } + + // Now write code to make the function call + + emit_func_call(name,d,l,f); + + // Return value if necessary + + if ((tm = typemap_lookup("out","tcl8",d,name,"_result","tcl_result"))) { + // Yep. Use it instead of the default + f.code << tm << "\n"; + } else if ((d->type != T_VOID) || (d->is_pointer)) { + if (!d->is_pointer) { + + // Function returns a "value" + + switch(d->type) { + // Is an integer + case T_BOOL: + case T_INT: + case T_SINT: + case T_SHORT: + case T_SSHORT: + case T_LONG : + case T_SLONG: + case T_SCHAR: + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + f.code << tab4 << "Tcl_SetObjResult(interp,Tcl_NewIntObj((long) _result));\n"; + break; + + // Is a single character. Assume we return it as a string + case T_CHAR : + f.code << tab4 << "Tcl_SetObjResult(interp,Tcl_NewStringObj(&_result,1));\n"; + break; + + // Floating point number + case T_DOUBLE : + case T_FLOAT : + f.code << tab4 << "Tcl_SetObjResult(interp,Tcl_NewDoubleObj((double) _result));\n"; + break; + + // User defined type + case T_USER : + + // Okay. We're returning malloced memory at this point. + // Probably dangerous, but who said safety was a good thing? + + // f.add_local("char","resultchar[256]"); + d->is_pointer++; + d->remember(); + f.code << tab4 << "Tcl_SetObjResult(interp,SWIG_NewPointerObj((void *) _result,SWIGTYPE" << d->print_mangle() << "));\n"; + + d->is_pointer--; + break; + + // Unknown type + default : + fprintf(stderr,"%s : Line %d: Unable to use return type %s in function %s.\n", + input_file, line_number, d->print_type(), name); + break; + } + } else { + + // Is a pointer return type + + if ((d->type == T_CHAR) && (d->is_pointer == 1)) { + // Return a character string + f.code << tab4 << "Tcl_SetObjResult(interp,Tcl_NewStringObj(_result,-1));\n"; + } else { + d->remember(); + f.code << tab4 << "Tcl_SetObjResult(interp,SWIG_NewPointerObj((void *) _result,SWIGTYPE" << d->print_mangle() << "));\n"; + } + } + } else { + // f.code << tab4 << "Tcl_SetResult(interp,"",TCL_STATIC);\n"; + } + + // Dump output argument code + f.code << outarg; + + // Dump the argument cleanup code + f.code << cleanup; + + // Look for any remaining cleanup + + if (NewObject) { + if ((tm = typemap_lookup("newfree","tcl8",d,iname,"_result",""))) { + f.code << tm << "\n"; + } + } + + if ((tm = typemap_lookup("ret","tcl8",d,name,"_result",""))) { + // Yep. Use it instead of the default + f.code << tm << "\n"; + } + + f.code << tab4 << "return TCL_OK;\n}"; + + // Substitute the cleanup code + f.code.replace("$cleanup",cleanup); + f.code.replace("$name",iname); + + // Dump out the function + + f.print(f_wrappers); + + // Now register the function with Tcl + + cmd_info << tab4 << "{ SWIG_prefix \"" << iname << "\", " << wname << ", NULL},\n"; + + // If there's a documentation entry, produce a usage string + + if (doc_entry) { + + static DocEntry *last_doc_entry = 0; + + // Use usage as description + doc_entry->usage << usage; + + // Set the cinfo field to specific a return type + + if (last_doc_entry != doc_entry) { + doc_entry->cinfo << "returns " << d->print_type(); + last_doc_entry = doc_entry; + } + } +} + +// ----------------------------------------------------------------------- +// TCL8::link_variable(char *name, char *iname, DataType *t, +// int ex) +// +// Create a TCL link to a variable. +// ----------------------------------------------------------------------- + +void TCL8::link_variable(char *name, char *iname, DataType *t) +{ + + static Hash setget; + String s; + char *tm, *tm1; + + // See if there were any typemaps + + tm = typemap_lookup("varin","tcl8",t,name,"",""); + tm1 = typemap_lookup("varout","tcl8",t,name,"",""); + if (tm || tm1) { + fprintf(stderr,"%s : Line %d. Warning. varin/varout typemap methods not supported.", + input_file, line_number); + } + + // Dump a collection of set/get functions suitable for variable tracing + if (!setget.lookup(t->print_type())) { + setget.add(t->print_type(),(void *)1); + WrapperFunction get; + WrapperFunction set; + set.def << "static char *_swig_" << t->print_mangle() << "_set(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags) {"; + get.def << "static char *_swig_" << t->print_mangle() << "_get(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags) {"; + t->is_pointer++; + get.add_local(t->print_type(),"addr"); + set.add_local(t->print_type(),"addr"); + set.code << tab4 << "addr = " << t->print_cast() << " clientData;\n"; + get.code << tab4 << "addr = " << t->print_cast() << " clientData;\n"; + t->is_pointer--; + set.add_local("char *","value"); + get.add_local("Tcl_Obj *","value"); + + set.code << tab4 << "value = Tcl_GetVar2(interp, name1, name2, flags);\n" + << tab4 << "if (!value) return NULL;\n"; + + if (!t->is_pointer) { + switch(t->type) { + case T_INT: + case T_SINT: + case T_SHORT: + case T_USHORT: + case T_SSHORT: + case T_LONG: + case T_SLONG: + case T_UCHAR: + case T_SCHAR: + case T_BOOL: + set.code << tab4 << "*(addr) = " << t->print_cast() << "atol(value);\n"; + break; + case T_UINT: + case T_ULONG: + set.code << tab4 << "*(addr) = " << t->print_cast() << "strtoul(value,0,0);\n"; + break; + case T_FLOAT: + case T_DOUBLE: + set.code << tab4 << "*(addr) = " << t->print_cast() << "atof(value);\n"; + break; + case T_USER: + // User defined type. We've got to extract it as a pointer and perform a copy. + + fprintf(stderr,"User defined type\n"); + break; + default: + fprintf(stderr,"Unknown type!\n"); + break; + } + } else { + if ((t->is_pointer == 1) && (t->type == T_CHAR)) { + /* A character string */ + + } + } + set.code << tab4 << "return NULL;\n" + << "}\n"; + + + if (!t->is_pointer) { + switch(t->type) { + case T_INT: + case T_SINT: + case T_UINT: + case T_SHORT: + case T_USHORT: + case T_SSHORT: + case T_LONG: + case T_ULONG: + case T_SLONG: + case T_UCHAR: + case T_SCHAR: + case T_BOOL: + get.add_local("Tcl_Obj *","value"); + get.code << tab4 << "value = Tcl_NewIntObj((int) *addr);\n" + << tab4 << "Tcl_SetVar2(interp,name1,name2,Tcl_GetStringFromObj(value,NULL), flags);\n" + << tab4 << "Tcl_DecrRefCount(value);\n"; + break; + case T_FLOAT: + case T_DOUBLE: + get.add_local("Tcl_Obj *","value"); + get.code << tab4 << "value = Tcl_NewDoubleObj((double) *addr);\n" + << tab4 << "Tcl_SetVar2(interp,name1,name2,Tcl_GetStringFromObj(value,NULL), flags);\n" + << tab4 << "Tcl_DecrRefCount(value);\n"; + break; + + case T_CHAR: + get.add_local("char","temp[4]"); + get.code << tab4 << "temp[0] = *addr; temp[1] = 0;\n" + << tab4 << "Tcl_SetVar2(interp,name1,name2,temp,flags);\n"; + break; + default: + break; + } + } + + get.code << tab4 << "return NULL;\n" + << "}\n"; + get.print(f_wrappers); + set.print(f_wrappers); + } + var_info << tab4 << "{ SWIG_prefix \"" << iname << "\", (void *) &" << name << ", _swig_" << t->print_mangle() << "_get,"; + + if (Status & STAT_READONLY) { + static int readonly = 0; + if (!readonly) { + WrapperFunction ro; + ro.def << "static char *_swig_readonly(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags) {"; + ro.code << tab4 << "return \"Variable is read-only\";\n"; + ro.code << "}\n"; + ro.print(f_wrappers); + readonly = 1; + } + var_info << "_swig_readonly},\n"; + } else { + var_info << "_swig_" << t->print_mangle() << "_set},\n"; + } +} + +#ifdef OLD + // Check the datatype. Must be a valid Tcl type (there aren't many) + + if (((t->type == T_INT) && (!t->is_pointer)) || + ((t->type == T_UINT) && (!t->is_pointer)) || + ((t->type == T_SINT) && (!t->is_pointer)) || + ((t->type == T_DOUBLE) && (!t->is_pointer)) || + ((t->type == T_BOOL) && (!t->is_pointer)) || + ((t->type == T_CHAR) && (t->is_pointer == 1))) { + + // This is a valid TCL type. + + if (t->type == T_UINT) + fprintf(stderr,"%s : Line %d : ** Warning. Linkage of unsigned type may be unsafe.\n", + input_file, line_number); + + // Now add symbol to the TCL interpreter + + switch(t->type) { + case T_CHAR : + if (t->arraystr) { + // Is an array. We have to do something different + fprintf(f_wrappers,"static char *tclvar%s = %s;\n",name,name); + s << "(char *) &tclvar" << name << ", TCL_LINK_STRING"; + } else { + s << "(char *) &" << name << ", TCL_LINK_STRING"; + } + break; + case T_BOOL: + case T_INT : + case T_UINT: + case T_SINT: + s << "(char *) &" << name << ", TCL_LINK_INT"; + break; + case T_DOUBLE : + s << "(char *) &" << name << ", TCL_LINK_DOUBLE"; + break; + default : + fprintf(f_init,"Fatal error. Internal error (Tcl:link_variable)\n"); + break; + } + + if (Status & STAT_READONLY) + s << " | TCL_LINK_READ_ONLY);\n"; + else + s << ");\n"; + + fprintf(f_init,"\t Tcl_LinkVar(%s, SWIG_prefix \"%s\", %s",interp_name, iname, s.get()); + + // Make a usage string for it + + if (doc_entry) { + doc_entry->usage << usage_var(iname,t); + doc_entry->cinfo = ""; + doc_entry->cinfo << "Global : " << t->print_type() << " " << name; + } + } else { + + // Have some sort of "other" type. + // We're going to emit some functions to set/get it's value instead + + emit_set_get(name,iname, t); + if (doc_entry) { + doc_entry->cinfo = ""; + doc_entry->cinfo << "Global : " << t->print_type() << " " << iname; + } + + // If shadow classes are enabled and we have a user-defined type + // that we know about, create a command for it. + + if (shadow) { + if ((t->type == T_USER) && (t->is_pointer < 1)) { + // See if the datatype is in our hash table + if (hash.lookup(t->name)) { + // Yep. Try to create a command for it + + postinit << tab4 << "{\n" + << tab8 << "char cmd[] = \"" + << (char *) hash.lookup(t->name) << " " << iname << " -this [" + << iname << "_get ]\";\n" + << tab8 << "Tcl_GlobalEval(interp,cmd);\n" + << tab4 << "}\n"; + } + } + } + } +} +#endif + +// ----------------------------------------------------------------------- +// TCL8::declare_const(char *name, char *iname, DataType *type, char *value) +// +// Makes a constant. Really just creates a variable and links to it. +// Tcl variable linkage allows read-only variables so we'll use that +// instead of just creating a Tcl variable. +// ------------------------------------------------------------------------ + +void TCL8::declare_const(char *name, char *, DataType *type, char *value) { + + int OldStatus = Status; // Save old status flags + DataType *t; + char var_name[256]; + char *tm; + String rvalue; + Status = STAT_READONLY; // Enable readonly mode. + + // Make a static variable; + + sprintf(var_name,"_wrap_const_%s",name); + + // See if there's a typemap + rvalue = value; + if ((type->type == T_CHAR) && (type->is_pointer == 1)) { + rvalue << "\""; + "\"" >> rvalue; + } + if ((type->type == T_CHAR) && (type->is_pointer == 0)) { + rvalue << "'"; + "'" >> rvalue; + } + if ((tm = typemap_lookup("const","tcl8",type,name,rvalue.get(),name))) { + // Yep. Use it instead of the default + fprintf(f_init,"%s\n",tm); + } else { + + // Create variable and assign it a value + + if (type->is_pointer == 0) { + switch(type->type) { + case T_BOOL: case T_INT: case T_SINT: case T_DOUBLE: + fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); + link_variable(var_name,name,type); + break; + case T_SHORT: + case T_LONG: + case T_SSHORT: + case T_SCHAR: + case T_SLONG: + fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); + fprintf(f_header,"static char *%s_char;\n", var_name); + if (CPlusPlus) + fprintf(f_init,"\t %s_char = new char[32];\n",var_name); + else + fprintf(f_init,"\t %s_char = (char *) malloc(32);\n",var_name); + + fprintf(f_init,"\t sprintf(%s_char,\"%%ld\", (long) %s);\n", var_name, var_name); + sprintf(var_name,"%s_char",var_name); + t = new DataType(T_CHAR); + t->is_pointer = 1; + link_variable(var_name,name,t); + delete t; + break; + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); + fprintf(f_header,"static char *%s_char;\n", var_name); + if (CPlusPlus) + fprintf(f_init,"\t %s_char = new char[32];\n",var_name); + else + fprintf(f_init,"\t %s_char = (char *) malloc(32);\n",var_name); + + fprintf(f_init,"\t sprintf(%s_char,\"%%lu\", (unsigned long) %s);\n", var_name, var_name); + sprintf(var_name,"%s_char",var_name); + t = new DataType(T_CHAR); + t->is_pointer = 1; + link_variable(var_name,name,t); + delete t; + break; + case T_FLOAT: + type->type = T_DOUBLE; + strcpy(type->name,"double"); + fprintf(f_header,"static %s %s = %s (%s);\n", type->print_type(), var_name, type->print_cast(), value); + link_variable(var_name,name,type); + break; + + case T_CHAR: + type->is_pointer++; + fprintf(f_header,"static %s %s = \"%s\";\n", type->print_type(), var_name, value); + link_variable(var_name,name,type); + type->is_pointer--; + break; + default: + fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number); + break; + } + } else { + // Have some sort of pointer value here + if ((type->type == T_CHAR) && (type->is_pointer == 1)) { + // Character string + fprintf(f_header,"static %s %s = \"%s\";\n", type->print_type(), var_name, value); + link_variable(var_name,name,type); + } else { + // Something else. Some sort of pointer value + fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); + fprintf(f_header,"static char *%s_char;\n", var_name); + if (CPlusPlus) + fprintf(f_init,"\t %s_char = new char[%d];\n",var_name,(int) strlen(type->print_mangle())+ 20); + else + fprintf(f_init,"\t %s_char = (char *) malloc(%d);\n",var_name, (int) strlen(type->print_mangle())+ 20); + + t = new DataType(T_CHAR); + t->is_pointer = 1; + fprintf(f_init,"\t SWIG_MakePtr(%s_char, (void *) %s,\"%s\");\n", + var_name, var_name, type->print_mangle()); + sprintf(var_name,"%s_char",var_name); + link_variable(var_name,name,t); + delete t; + } + } + } + + // Create a documentation entry for this + + if (doc_entry) { + doc_entry->usage = ""; // Destroy any previous information from linking + doc_entry->usage << usage_const(name, type, value); + doc_entry->cinfo = ""; + doc_entry->cinfo << "Constant : " << type->print_type(); + } + + Status = OldStatus; +} + +// ---------------------------------------------------------------------- +// TCL8::usage_var(char *iname, DataType *t, char **s) +// +// Produces a usage string for a tcl variable. Stores it in s +// ---------------------------------------------------------------------- + +char *TCL8::usage_var(char *iname, DataType *t) { + + static char temp[1024]; + + if (!nspace) { + sprintf(temp,"$%s%s", prefix, iname); + } else { + sprintf(temp,"%s::%s", ns_name, iname); + } + if (!(((t->type == T_INT) && (!t->is_pointer)) || + ((t->type == T_UINT) && (!t->is_pointer)) || + ((t->type == T_DOUBLE) && (!t->is_pointer)) || + ((t->type == T_BOOL) && (!t->is_pointer)) || + ((t->type == T_CHAR) && (t->is_pointer)))) { + /* We emitted a pair of set/get functions instead. Doc will be generated for that */ + return temp; + } + return temp; +} + + + +// --------------------------------------------------------------------------- +// char *TCL8::usage_string(char *iname, DataType *t, ParmList *l), +// +// Generates a generic usage string for a Tcl function. +// --------------------------------------------------------------------------- + +char * TCL8::usage_string(char *iname, DataType *, ParmList *l) { + + static String temp; + Parm *p; + int i, numopt,pcount; + + temp = ""; + temp << iname << " "; + + /* Now go through and print parameters */ + i = 0; + pcount = l->nparms; + numopt = l->numopt(); + p = l->get_first(); + while (p != 0) { + + // Only print an argument if not ignored + + if (!typemap_check("ignore","tcl8",p->t,p->name)) { + if (i >= (pcount-numopt)) + temp << "?"; + + /* If parameter has been named, use that. Otherwise, just print a type */ + + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + if (strlen(p->name) > 0) { + temp << p->name; + } + else { + temp << "{ " << p->t->print_type() << " }"; + } + } + if (i >= (pcount-numopt)) + temp << "?"; + temp << " "; + i++; + } + p = l->get_next(); + } + return temp; +} + +// --------------------------------------------------------------------------- +// char *TCL8::usage_func(char *iname, DataType *t, ParmList *l), +// +// Produces a usage string for a function in Tcl +// --------------------------------------------------------------------------- + +char * TCL8::usage_func(char *iname, DataType *t, ParmList *l) { + + String temp; + + if (nspace) { + temp << ns_name << "::" << iname; + } else { + temp << prefix << iname; + } + return usage_string(temp,t,l); +} + +// ----------------------------------------------------------------- +// TCL8::usage_const(char *name, DataType *type, char *value) +// char **s) +// +// Makes a usage string and returns it +// ----------------------------------------------------------------- + +char *TCL8::usage_const(char *name, DataType *, char *value) { + static String temp; + temp = ""; + if (nspace) { + temp << ns_name << "::" << name << " = " << value; + } else { + temp << "$" << prefix << name << " = " << value; + } + return temp.get(); +} + +// ------------------------------------------------------------------- +// TCL8::add_native(char *name, char *funcname) +// +// This adds an already written Tcl wrapper function to our +// initialization function. +// ------------------------------------------------------------------- + + +void TCL8::add_native(char *name, char *funcname) { + + fprintf(f_init,"\t Tcl_CreateCommand(%s, SWIG_prefix \"%s\", %s, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);\n",interp_name, name, funcname); + + if (doc_entry) { + if (nspace) + doc_entry->usage << ns_name << "::" << name << " args"; + else + doc_entry->usage << prefix << name << " args"; + + doc_entry->cinfo << "Native method : " << funcname; + } + +} + +// ------------------------------------------------------------------- +// TCL8::pragma(char *lname, char *name, char *value) +// +// Handle pragmas. +// -------------------------------------------------------------------- + +void TCL8::pragma(char *, char *, char *) { + +} + +// --------------------------------------------------------------------- +// C++ Handling +// +// The following functions provide some support for C++ classes and +// C structs. +// --------------------------------------------------------------------- + +void TCL8::cpp_open_class(char *classname, char *rename, char *ctype, int strip) { + + this->Language::cpp_open_class(classname,rename,ctype,strip); + + if (shadow) { + static int included_object = 0; + if (!included_object) { + if (insert_file("object.swg",f_header) == -1) { + fprintf(stderr,"SWIG : Fatal error. Unable to locate 'object.swg' in SWIG library.\n"); + SWIG_exit(1); + } + included_object = 1; + } + + attributes = "static _swig_attribute _swig_"; + attributes << classname << "_attributes[] = {\n"; + + methods = "static _swig_method _swig_"; + methods << classname << "_methods[] = {\n"; + + have_constructor = 0; + have_destructor = 0; + + if (rename) + class_name = copy_string(rename); + else + class_name = copy_string(classname); + + base_class = (char *) 0; + if (!strip) { + class_type = new char[strlen(ctype)+2]; + sprintf(class_type,"%s ", ctype); + } else + class_type = ""; + + real_classname = copy_string(classname); + } +} + +void TCL8::cpp_close_class() { + String code,temp; + DataType *t; + + this->Language::cpp_close_class(); + if (shadow) { + + t = new DataType; + sprintf(t->name,"%s%s", class_type, real_classname); + t->type = T_USER; + t->is_pointer = 1; + + if (have_destructor) { + code << "static void _swig_delete_" << class_name << "(void *obj) {\n" + << tab4 << name_destroy(class_name) << "((" << t->print_type() << ") obj);\n" + << "}\n"; + } + + methods << " {0,0}\n" + << "};\n"; + code << methods; + + attributes << " {0,0,0}\n" + << "};\n"; + code << attributes; + + code << "static _swig_class _wrap_class_" << class_name << " = { \"" << class_name + << "\", &SWIGTYPE" << t->print_mangle() << ","; + + if (have_constructor) { + code << name_wrapper(name_construct(class_name),prefix); + } else { + code << "0"; + } + if (have_destructor) { + code << ", _swig_delete_" << class_name; + } else { + code << ",0"; + } + code << ", _swig_" << class_name << "_methods, _swig_" << class_name << "_attributes };\n"; + fprintf(f_wrappers,"%s", code.get()); + + cmd_info << tab4 << "{ SWIG_prefix \"" << class_name << "\", SwigObjectCmd, &_wrap_class_" << class_name << "},\n"; + } +} + +void TCL8::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) { + + char *realname; + String temp; + char *rname; + + this->Language::cpp_member_func(name,iname,t,l); + + if (shadow) { + if (iname) + realname = iname; + else + realname = name; + + // Add stubs for this member to our class handler function + + temp = ""; + temp << name_member(realname,class_name); + rname = (char *) repeatcmd.lookup(temp); + if (!rname) + rname = name_wrapper(temp.get(),prefix); + + methods << tab4 << "{\"" << realname << "\", " << rname << "}, \n"; + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->usage << usage_string(realname,t,l); + } + } +} + +void TCL8::cpp_variable(char *name, char *iname, DataType *t) { + char *realname; + String temp; + char *rname; + + this->Language::cpp_variable(name, iname, t); + + if (shadow) { + if (iname) + realname = iname; + else + realname = name; + + char *bc = class_name; + + attributes << tab4 << "{ \"-" << realname << "\","; + + // Try to figure out if there is a wrapper for this function + temp = ""; + temp << name_get(name_member(realname,bc)); + rname = (char *) repeatcmd.lookup(temp); + if (!rname) + rname = name_wrapper(temp.get(),prefix); + attributes << rname << ", "; + + if (!(Status & STAT_READONLY)) { + temp = ""; + temp << name_set(name_member(realname,bc)); + rname = (char *) repeatcmd.lookup(temp); + if (!rname) + rname = name_wrapper(temp.get(),prefix); + attributes << rname << "},\n"; + } else { + attributes << "0 },\n"; + } + if (doc_entry){ + doc_entry->usage = ""; + doc_entry->usage << "-" << realname << "\n"; + } + } +} + +void TCL8::cpp_constructor(char *name, char *iname, ParmList *l) { + this->Language::cpp_constructor(name,iname,l); + + if (shadow) { + if ((!have_constructor) && (doc_entry)) { + doc_entry->usage = ""; + doc_entry->usage << class_name << usage_string(" name",0,l); + } + have_constructor = 1; + } +} +void TCL8::cpp_destructor(char *name, char *newname) { + this->Language::cpp_destructor(name,newname); + if (shadow) { + if (!have_destructor) { + if (doc_entry) { + doc_entry->usage = "rename obj {}"; + } + } + have_destructor = 1; + } +} + +void TCL8::cpp_inherit(char **baseclass, int) { + this->Language::cpp_inherit(baseclass); +} + +void TCL8::cpp_declare_const(char *name, char *iname, DataType *type, char *value) { + this->Language::cpp_declare_const(name,iname,type,value); +} + +// -------------------------------------------------------------------------------- +// TCL8::add_typedef(DataType *t, char *name) +// +// This is called whenever a typedef is encountered. When shadow classes are +// used, this function lets us discovered hidden uses of a class. For example : +// +// struct FooBar { +// ... +// } +// +// typedef FooBar *FooBarPtr; +// +// -------------------------------------------------------------------------------- + +void TCL8::add_typedef(DataType *t, char *name) { + + if (!shadow) return; + + // First check to see if there aren't too many pointers + + if (t->is_pointer > 1) return; + if (hash.lookup(name)) return; // Already added + + // Now look up the datatype in our shadow class hash table + + if (hash.lookup(t->name)) { + + // Yep. This datatype is in the hash + // Put this types 'new' name into the hash + hash.add(name,copy_string((char *) hash.lookup(t->name))); + } +} + +// ----------------------------------------------------------------------- +// TCL8::cpp_class_decl(char *name, char *rename, char *type) +// +// Treatment of an empty class definition. Used to handle +// shadow classes across modules. +// ----------------------------------------------------------------------- + +void TCL8::cpp_class_decl(char *name, char *rename, char *type) { + char temp[256]; + this->Language::cpp_class_decl(name,rename, type); + + if (shadow) { + hash.add(name,copy_string(rename)); + // Add full name of datatype to the hash table + if (strlen(type) > 0) { + sprintf(temp,"%s %s", type, name); + hash.add(temp,copy_string(rename)); + } + } +} diff --git a/SWIG/Source/Modules1.1/tcl8.h b/SWIG/Source/Modules1.1/tcl8.h new file mode 100644 index 000000000..12fec6a34 --- /dev/null +++ b/SWIG/Source/Modules1.1/tcl8.h @@ -0,0 +1,102 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/************************************************************************** + * class TCL8 + * + * A TCL implementation for Tcl 8.0. Basically the same as the other + * Tcl module, but with different code generation. + **************************************************************************/ + +class TCL8 : public Language { +private: + char interp_name[256]; + char *prefix; // Package prefix + char *module; // Name of the module + char *tcl_path; + char *init_name; + int nspace; + void get_pointer(char *iname, char *srcname, char *src, char *dest, DataType *t, + String &f, char *ret); + char *char_result; + char *usage_func(char *, DataType *, ParmList *); + char *usage_string(char *, DataType *, ParmList *); + char *usage_var(char *, DataType *); + char *usage_const(char *, DataType *, char *); + + // C++ handling + + int have_constructor; + int have_destructor; + String methods; + String attributes; + String postinit; + int shadow; + char *class_name; + char *class_type; + char *real_classname; + char *base_class; + Hash hash; + Hash repeatcmd; + +public : + TCL8() { + prefix = 0; + module = 0; + init_name = 0; + nspace = 0; + shadow = 1; + char_result = "TCL_VOLATILE"; + tcl_path = "tcl"; + sprintf(interp_name,"interp"); + class_name = 0; + class_type = 0; + real_classname = 0; + base_class = 0; + }; + void parse_args(int, char *argv[]); + void parse(); + void create_function(char *, char *, DataType *, ParmList *); + void link_variable(char *, char *, DataType *); + void declare_const(char *, char *, DataType *, char *); + void initialize(void); + void headers(void); + void close(void); + void set_module(char *,char **); + void set_init(char *); + void add_native(char *, char *); + void pragma(char *,char *, char *); + void create_command(char *, char *); + + // Stubs for processing C++ classes in Tcl + + void cpp_open_class(char *classname, char *rename, char *ctype, int strip); + void cpp_close_class(); + void cpp_member_func(char *name, char *iname, DataType *t, ParmList *l); + void cpp_variable(char *name, char *iname, DataType *t); + void cpp_constructor(char *name, char *iname, ParmList *l); + void cpp_destructor(char *name, char *newname); + void cpp_inherit(char **baseclass, int mode = INHERIT_ALL); + void cpp_declare_const(char *name, char *iname, DataType *type, char *value); + void add_typedef(DataType *, char *); + void cpp_class_decl(char *, char *, char *); + +}; + + + + + + diff --git a/SWIG/Source/Modules1.1/wrap.h b/SWIG/Source/Modules1.1/wrap.h new file mode 100644 index 000000000..1383b7519 --- /dev/null +++ b/SWIG/Source/Modules1.1/wrap.h @@ -0,0 +1,38 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * wrap.h + ***********************************************************************/ + +#include "swig.h" + +#ifndef SWIG_LIB +#define SWIG_LIB = "./swig_lib" +#endif + +#ifndef SWIG_LANG +#define SWIG_LANG TCL8 +#endif + +#ifndef SWIG_DOC +#define SWIG_DOC ASCII +#endif + + + + + diff --git a/SWIG/Source/Preprocessor/Makefile.in b/SWIG/Source/Preprocessor/Makefile.in new file mode 100644 index 000000000..830ef6c72 --- /dev/null +++ b/SWIG/Source/Preprocessor/Makefile.in @@ -0,0 +1,24 @@ +# Generated automatically from Makefile.in by configure. + +CC = @CC@ +AR = @AR@ +RANLIB = @RANLIB@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +RPATH = @RPATH@ +SO = @SO@ +CCSHARED = @CCSHARED@ +LDSHARED = @LDSHARED@ +INCLUDE = -I. -I../Core -I../DOH/Include + +SRCS = expr.c cpp.c +OBJS = expr.o cpp.o + +.c.o: + $(CC) $(CCSHARED) $(INCLUDE) $(CFLAGS) -c -o $*.o $< + +all: $(OBJS) + +clean: + rm -f *.o *~ core *.so *.a + diff --git a/SWIG/Source/Preprocessor/cpp.c b/SWIG/Source/Preprocessor/cpp.c new file mode 100644 index 000000000..78ad5f100 --- /dev/null +++ b/SWIG/Source/Preprocessor/cpp.c @@ -0,0 +1,1195 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + +#include "swigcpp.h" +#include + +/* ----------------------------------------------------------------------------- + * $Header$ + * + * File : cpp.c + * + * The SWIG Preprocessor. This works almost exactly like the C preprocessor except + * for a number of extensions: + * + * - SWIG directives such as %include, %extern, and %import are recognized + * - A new macro %define ... %enddef is provided to make it easier to + * write multi-line macros. + * - No preprocessing is performed inside %{ ... %} blocks. + * - Lines beginning with %#... are stripped to #... and passed through + * unmodified. + * ----------------------------------------------------------------------------- */ + +static DOH *cpp = 0; /* C preprocessor data */ +static int include_all = 1; /* Follow all includes */ +static int single_include = 1; /* Only include each file once */ +static int silent_errors = 0; +static DOH *included_files = 0; + +/* Handle an error */ + +void cpp_error(DOH *file, int line, char *fmt, ...) { + va_list ap; + if (silent_errors) return; + va_start(ap,fmt); + if (line > 0) { + Printf(stderr,"%s:%d ", file, line); + } else { + Printf(stderr,"%s:EOF ",file); + } + vPrintf(stderr,fmt,ap); + va_end(ap); +} + +/* Test a character to see if it starts an identifier */ +static int +isidentifier(char c) { + if ((isalpha(c)) || (c == '_') || (c == '$')) return 1; + else return 0; +} + +/* Test a character to see if it valid in an identifier (after the first letter) */ +static int +isidchar(char c) { + if ((isalnum(c)) || (c == '_') || (c == '$')) return 1; + else return 0; +} + +/* Skip whitespace */ +static void +skip_whitespace(DOH *s, DOH *out) { + int c; + while ((c = Getc(s)) != EOF) { + if (!isspace(c)) { + Ungetc(c,s); + break; + } else if (out) Putc(c,out); + } +} + +/* Skip to a specified character taking line breaks into account */ +static int +skip_tochar(DOH *s, int ch, DOH *out) { + int c; + while ((c = Getc(s)) != EOF) { + if (out) Putc(c,out); + if (c == ch) break; + if (c == '\\') { + c = Getc(s); + if ((c != EOF) && (out)) Putc(c,out); + } + } + if (c == EOF) return -1; + return 0; +} + +static void +copy_location(DOH *s1, DOH *s2) { + Setfile(s2,Getfile(s1)); + Setline(s2,Getline(s1)); +} + +static DOH *cpp_include(DOH *fn) { + DOH *s; + if (single_include) { + if (Getattr(included_files,fn)) return 0; + Setattr(included_files,fn,fn); + } + s = SWIG_include(fn); + if (!s) { + Seek(fn,0,SEEK_SET); + cpp_error(Getfile(fn),Getline(fn),"Unable to find '%s'\n", fn); + } else { + Seek(s,0,SEEK_SET); + } + return s; +} + +/* ----------------------------------------------------------------------------- + * void SWIG_cpp_init() - Initialize the preprocessor + * ----------------------------------------------------------------------------- */ +void SWIG_cpp_init() { + DOH *s; + cpp = NewHash(); + s = NewHash(); + Setattr(cpp,"symbols",s); + SWIG_expr_init(); /* Initialize the expression evaluator */ + included_files = NewHash(); +} +/* ----------------------------------------------------------------------------- + * void SWIG_cpp_include_all() - Instruct preprocessor to include all files + * ----------------------------------------------------------------------------- */ +void SWIG_cpp_include_all(int a) { + include_all = a; +} + +/* ----------------------------------------------------------------------------- + * DOH *SWIG_cpp_define(DOH *str, int swigmacro) + * + * Defines a new C preprocessor symbol. swigmacro specifies whether or not the macro has + * SWIG macro semantics. + * ----------------------------------------------------------------------------- */ + +DOH *SWIG_cpp_define(DOH *str, int swigmacro) +{ + DOH *macroname = 0, *argstr = 0, *macrovalue = 0, *arglist = 0, *macro = 0, *symbols = 0, *file = 0, *s, *m1; + int c, line; + + assert(cpp); + assert(str); + + /* First make sure that string is actually a string */ + if (String_check(str)) { + s = Copy(str); + copy_location(str,s); + str = s; + } else { + str = NewString((char *) str); + } + line = Getline(str); + file = Getfile(str); + + /* Printf(stdout,"%s:%d '%s'\n", file,line,str); */ + + /* Skip over any leading whitespace */ + skip_whitespace(str,0); + + /* Now look for a macro name */ + macroname = NewString(""); + while ((c = Getc(str)) != EOF) { + if (c == '(') { + argstr = NewString(""); + copy_location(str,argstr); + /* It is a macro. Go extract it's argument string */ + while ((c = Getc(str)) != EOF) { + if (c == ')') break; + else Putc(c,argstr); + } + if (c != ')') { + cpp_error(Getfile(str),Getline(str), "Missing \')\' in macro parameters\n"); + goto macro_error; + } + break; + } else if (isidchar(c)) { + Putc(c,macroname); + } else if (isspace(c)) { + break; + } else { + cpp_error(Getfile(str),Getline(str),"Illegal character in macro name\n"); + goto macro_error; + } + } + if (!swigmacro) + skip_whitespace(str,0); + macrovalue = NewString(""); + while ((c = Getc(str)) != EOF) { + Putc(c,macrovalue); + } + + /* If there are any macro arguments, convert into a list */ + if (argstr) { + DOH *argname; + arglist = NewList(); + Seek(argstr,0,SEEK_SET); + argname = NewString(""); + while ((c = Getc(argstr)) != EOF) { + if (c == ',') { + Append(arglist,argname); + argname = NewString(""); + } else if (isidchar(c)) { + Putc(c,argname); + } else if (!isspace(c)) { + cpp_error(Getfile(str),Getline(str),"Illegal character in macro name\n"); + goto macro_error; + } + } + if (Len(argname)) { + Append(arglist,argname); + } + } + + if (!swigmacro) { + String_replace(macrovalue,"\\\n"," ", DOH_REPLACE_ANY); + } + /* Get rid of whitespace surrounding # */ + String_replace(macrovalue,"#","\001",DOH_REPLACE_NOQUOTE); + while(strstr(Char(macrovalue),"\001 ")) { + String_replace(macrovalue,"\001 ","\001", DOH_REPLACE_NOQUOTE); + } + while(strstr(Char(macrovalue)," \001")) { + String_replace(macrovalue," \001","\001", DOH_REPLACE_NOQUOTE); + } + + /* Replace '##' with a special token */ + String_replace(macrovalue,"\001\001","\002", DOH_REPLACE_NOQUOTE); + + /* Go create the macro */ + macro = NewHash(); + Setattr(macro,"name", macroname); + if (arglist) + Setattr(macro,"args",arglist); + Setattr(macro,"value",macrovalue); + Setline(macro,line); + Setfile(macro,file); + if (swigmacro) { + Setattr(macro,"swigmacro","1"); + } + symbols = Getattr(cpp,"symbols"); + if ((m1 = Getattr(symbols,macroname))) { + if (Cmp(Getattr(m1,"value"),macrovalue)) + cpp_error(Getfile(str),Getline(str),"Macro '%s' redefined. Previous definition in \'%s\', Line %d\n", macroname, Getfile(m1), Getline(m1)); + } + Setattr(symbols,macroname,macro); + return macro; + +macro_error: + return 0; +} + +/* ----------------------------------------------------------------------------- + * void SWIG_cpp_undef(DOH *str) + * + * Undefines a macro. + * ----------------------------------------------------------------------------- */ +void SWIG_cpp_undef(DOH *str) +{ + DOH *symbols; + assert(cpp); + symbols = Getattr(cpp,"symbols"); + Delattr(symbols,str); +} + +/* ----------------------------------------------------------------------------- + * DOH *find_args(DOH *s) + * + * Isolates macro arguments and returns them in a list. For each argument, + * leading and trailing whitespace is stripped (ala K&R, pg. 230). + * ----------------------------------------------------------------------------- */ +static DOH * +find_args(DOH *s) +{ + DOH *args, *str; + int c, level; + + /* Create a new list */ + args = NewList(); + copy_location(s,args); + + /* First look for a '(' */ + skip_whitespace(s,0); + + /* Now see if the next character is a '(' */ + c = Getc(s); + if (c != '(') { + /* Not a macro, bail out now! */ + cpp_error(Getfile(s),Getline(s),"Missing macro arguments\n"); + return args; + } + c = Getc(s); + /* Okay. This appears to be a macro so we will start isolating arguments */ + while (c != EOF) { + if (isspace(c)) { + skip_whitespace(s,0); /* Skip leading whitespace */ + c = Getc(s); + } + str = NewString(""); + copy_location(s,str); + level = 0; + while (c != EOF) { + if (c == '\"') { + Putc(c,str); + skip_tochar(s,'\"',str); + c = Getc(s); + continue; + } else if (c == '\'') { + Putc(c,str); + skip_tochar(s,'\'',str); + c = Getc(s); + continue; + } + if ((c == ',') && (level == 0)) break; + if ((c == ')') && (level == 0)) break; + Putc(c,str); + if (c == '(') level++; + if (c == ')') level--; + c = Getc(s); + } + if (level > 0) { + goto unterm; + } + String_chop(str); + if (Len(args) || Len(str)) + Append(args,str); + + /* if (Len(str) && (c != ')')) + Append(args,str); */ + + if (c == ')') return args; + c = Getc(s); + } + unterm: + cpp_error(Getfile(args),Getline(args),"Unterminated macro call.\n"); + return args; +} + +/* ----------------------------------------------------------------------------- + * DOH *get_filename(DOH *str) + * + * Read a filename from str. A filename can be enclose in quotes, angle brackets, + * or bare. + * ----------------------------------------------------------------------------- */ + +static DOH * +get_filename(DOH *str) { + DOH *fn; + int c; + + skip_whitespace(str,0); + fn = NewString(""); + copy_location(str,fn); + c = Getc(str); + if (c == '\"') { + while (((c = Getc(str)) != EOF) && (c != '\"')) Putc(c,fn); + } else if (c == '<') { + while (((c = Getc(str)) != EOF) && (c != '>')) Putc(c,fn); + } else { + Putc(c,fn); + while (((c = Getc(str)) != EOF) && (!isspace(c))) Putc(c,fn); + } + Seek(fn,0,SEEK_SET); + return fn; +} + +/* ----------------------------------------------------------------------------- + * DOH *expand_macro(DOH *name, DOH *args) + * + * Perform macro expansion and return a new string. Returns NULL if some sort + * of error occurred. + * ----------------------------------------------------------------------------- */ + +DOH *expanded_value = 0; + +DOH * +expand_macro(DOH *name, DOH *args) +{ + DOH *symbols, *ns, *macro, *margs, *mvalue, *temp, *tempa, *e; + DOH *swig_cpp_replace(DOH *); + DOH *SWIG_cpp_parse(DOH *); + int i, l; + + symbols = Getattr(cpp,"symbols"); + if (!symbols) return 0; + + /* See if the name is actually defined */ + macro = Getattr(symbols,name); + if (!macro) return 0; + if (Getattr(macro,"*expanded*")) { + ns = NewString(""); + Printf(ns,"%s",name); + if (args) { + Putc('(',ns); + for (i = 0; i < Len(args); i++) { + Printf(ns,"%s",Getitem(args,i)); + if (i < (Len(args) -1)) Putc(',',ns); + } + Putc(')',ns); + } + return ns; + } + + /* Get macro arguments and value */ + mvalue = Getattr(macro,"value"); + assert(mvalue); + margs = Getattr(macro,"args"); + + /* If there are arguments, see if they match what we were given */ + if ((margs) && (Len(margs) != Len(args))) { + if (Len(margs) > 1) + cpp_error(Getfile(args),Getline(args),"Macro '%s' expects %d arguments\n", name, Len(margs)); + else if (Len(margs) == 1) + cpp_error(Getfile(args),Getline(args),"Macro '%s' expects 1 argument\n", name); + else + cpp_error(Getfile(args),Getline(args),"Macro '%s' expects no arguments\n", name); + return 0; + } + + /* Copy the macro value */ + ns = Copy(mvalue); + copy_location(mvalue,ns); + + /* Tag the macro as being expanded. This is to avoid recursion in + macro expansion */ + + if (!expanded_value) { + expanded_value = NewString(""); + DohIntern(expanded_value); + } + Setattr(macro,"*expanded*",expanded_value); + + temp = NewString(""); + tempa = NewString(""); + if (margs) { + l = Len(margs); + for (i = 0; i < l; i++) { + DOH *arg, *aname; + arg = Getitem(args,i); /* Get an argument value */ + aname = Getitem(margs,i); /* Get macro argument name */ + if (strstr(Char(ns),"\001")) { + /* Try to replace a quoted version of the argument */ + Clear(temp); + Clear(tempa); + Printf(temp,"\001%s", aname); + Printf(tempa,"\"%s\"",arg); + String_replace(ns, temp, tempa, DOH_REPLACE_ANY); + } + String_replace(ns, aname, arg, DOH_REPLACE_ID); + } + } + String_replace(ns,"\002","",DOH_REPLACE_ANY); /* Get rid of concatenation tokens */ + String_replace(ns,"\001","#",DOH_REPLACE_ANY); /* Put # back (non-standard C) */ + + /* Expand this macro even further */ + e = swig_cpp_replace(ns); + Delattr(macro,"*expanded*"); + if (Getattr(macro,"swigmacro")) { + DOH *g; + DOH *f = NewString(""); + Printf(f,"%%macro %s, \"%s\", %d {\n", name, Getfile(macro), Getline(macro)); + Seek(e,0,SEEK_SET); + copy_location(macro,e); + g = SWIG_cpp_parse(e); + Printf(f,"%s\n", g); + Printf(f,"}\n"); + e = f; + } + return e; +} + +/* ----------------------------------------------------------------------------- + * DOH *swig_cpp_replace(DOH *s) + * + * Performs a macro substitution on a string s. Returns a new string with + * substitutions applied. This function works by walking down s and looking + * for identifiers. When found, a check is made to see if they are macros + * which are then expanded. + * ----------------------------------------------------------------------------- */ + +DOH * +swig_cpp_replace(DOH *s) +{ + DOH *ns, *id, *symbols, *m; + int c, i, state = 0; + + assert(cpp); + symbols = Getattr(cpp,"symbols"); + + ns = NewString(""); + copy_location(s,ns); + Seek(s,0,SEEK_SET); + id = NewString(""); + + /* Try to locate identifiers in s and replace them with macro replacements */ + while ((c = Getc(s)) != EOF) { + switch (state) { + case 0: + if (isidentifier(c)) { + Clear(id); + copy_location(s,id); + Putc(c,id); + state = 1; + } else if (c == '\"') { + Putc(c,ns); + skip_tochar(s,'\"',ns); + } else if (c == '\'') { + Putc(c,ns); + skip_tochar(s,'\'',ns); + } else if (c == '/') { + Putc(c,ns); + state = 10; + } else { + Putc(c,ns); + } + break; + case 1: /* An identifier */ + if (isidchar(c)) { + Putc(c,id); + state = 1; + } else { + /* We found the end of a valid identifier */ + Ungetc(c,s); + /* See if this is the special "defined" macro */ + if (Cmp(id,"defined") == 0) { + DOH *args; + /* See whether or not a paranthesis has been used */ + skip_whitespace(s,0); + c = Getc(s); + if (c == '(') { + Seek(s,-1,SEEK_CUR); + args = find_args(s); + } else { + DOH *arg = 0; + args = NewList(); + arg = NewString(""); + while ((c = Getc(s)) != EOF) { + if (!isidchar(c)) { + Seek(s,-1,SEEK_CUR); + break; + } + Putc(c,arg); + } + Append(args,arg); + } + if (!args) { + cpp_error(Getfile(id),Getline(id),"No arguments given to defined()\n"); + state = 0; + break; + } + for (i = 0; i < Len(args); i++) { + DOH *o = Getitem(args,i); + if (!Getattr(symbols,o)) { + break; + } + } + if (i < Len(args)) Putc('0',ns); + else Putc('1',ns); + state = 0; + break; + } + if (Cmp(id,"__LINE__") == 0) { + Printf(ns,"%d",Getline(s)); + state = 0; + break; + } + if (Cmp(id,"__FILE__") == 0) { + Printf(ns,"\"%s\"",Getfile(s)); + state = 0; + break; + } + /* See if the macro is defined in the preprocessor symbol table */ + if ((m = Getattr(symbols,id))) { + DOH *args = 0; + DOH *e; + /* See if the macro expects arguments */ + if (Getattr(m,"args")) { + /* Yep. We need to go find the arguments and do a substitution */ + args = find_args(s); + } else { + args = 0; + } + e = expand_macro(id,args); + if (e) { + Printf(ns,"%s",e); + } + } else { + Printf(ns,"%s",id); + } + state = 0; + } + break; + case 10: + if (c == '/') state = 11; + else if (c == '*') state = 12; + else { + Ungetc(c,s); + state = 0; + break; + } + Putc(c,ns); + break; + case 11: + Putc(c,ns); + if (c == '\n') state = 0; + break; + case 12: + Putc(c,ns); + if (c == '*') state = 13; + break; + case 13: + Putc(c,ns); + if (c == '/') state = 0; + else if (c != '*') state = 12; + break; + default: + state = 0; + break; + } + } + + /* Identifier at the end */ + if (state == 1) { + /* See if this is the special "defined" macro */ + if (Cmp(id,"defined") == 0) { + cpp_error(Getfile(id),Getline(id),"No arguments given to defined()\n"); + } else if ((m = Getattr(symbols,id))) { + DOH *e; + /* Yes. There is a macro here */ + /* See if the macro expects arguments */ + if (Getattr(m,"args")) { + cpp_error(Getfile(id),Getline(id),"Macro arguments expected.\n"); + } + e = expand_macro(id,0); + Printf(ns,"%s",e); + } else { + Printf(ns,"%s",id); + } + } + return ns; +} + + +/* ----------------------------------------------------------------------------- + * int check_id(DOH *s) + * + * Checks the string s to see if it contains any unresolved identifiers. This + * function contains the heuristic that determines whether or not a macro + * definition passes through the preprocessor as a constant declaration. + * ----------------------------------------------------------------------------- */ +static int +check_id(DOH *s) +{ + int c, state = 0; + Seek(s,0,SEEK_SET); + while ((c = Getc(s)) != EOF) { + switch(state) { + case 0: + if (isdigit(c)) state = 1; + else if (isidentifier(c)) return 1; + else if (c == '\"') skip_tochar(s,'\"',0); + else if (c == '\'') skip_tochar(s,'\'',0); + else if (c == '/') state = 3; + break; + case 1: + if ((c == 'L') || (c == 'U') || (c == 'F') || (c == 'l') || (c == 'u')) state = 2; + else if (isidentifier(c)) return 1; + else if (!isdigit(c)) state = 0; + break; + case 2: + if ((c == 'L') || (c == 'U') || (c == 'F') || (c == 'l') || (c == 'u')) state = 2; + else { + Ungetc(c,s); + state = 0; + } + break; + case 3: + if (c == '*') state = 10; + else if (c == '/') state = 20; + else { + Ungetc(c,s); + state = 0; + } + break; + case 10: + if (c == '*') state = 11; + break; + case 11: + if (c == '/') state = 0; + else if (c != '*') state = 10; + break; + case 20: + if (c == '\n') state = 0; + break; + } + } + return 0; +} + +/* addline(). Utility function for adding lines to a chunk */ +static void +addline(DOH *s1, DOH *s2, int allow) +{ + if (allow) { + Append(s1,s2); + } else { + char *c = Char(s2); + while (*c) { + if (*c == '\n') Putc('\n',s1); + c++; + } + } +} + +static void add_chunk(DOH *ns, DOH *chunk, int allow) { + DOH *echunk; + Seek(chunk,0,SEEK_SET); + if (allow) { + echunk = swig_cpp_replace(chunk); + addline(ns,echunk,allow); + Delete(echunk); + } else { + addline(ns,chunk,0); + } + Clear(chunk); +} + +/* ----------------------------------------------------------------------------- + * DOH *SWIG_cpp_parse(DOH *s) + * + * Parses the string s. Returns a new string containing the preprocessed version. + * + * Parsing rules : + * 1. Lines starting with # are C preprocessor directives + * 2. Macro expansion inside strings is not allowed + * 3. All code inside false conditionals is changed to blank lines + * 4. Code in %{, %} is not parsed because it may need to be + * included inline (with all preprocessor directives included). + * ----------------------------------------------------------------------------- */ + +DOH * +SWIG_cpp_parse(DOH *s) +{ + DOH *ns; /* New string containing the preprocessed text */ + DOH *chunk, *symbols, *sval, *decl; + DOH *id = 0, *value = 0, *comment = 0; + int i, state, val, e, c; + int start_line = 0; + int allow = 1; + int level = 0; + int mask = 0; + int start_level = 0; + int cpp_lines = 0; + int cond_lines[256]; + int scp; + + ns = NewString(""); /* Return result */ + scp = NewScope(); + + decl = NewString(""); + id = NewString(""); + value = NewString(""); + comment = NewString(""); + chunk = NewString(""); + copy_location(s,chunk); + copy_location(s,ns); + symbols = Getattr(cpp,"symbols"); + + state = 0; + while ((c = Getc(s)) != EOF) { + switch(state) { + case 0: /* Initial state - in first column */ + /* Look for C preprocessor directives. Otherwise, go directly to state 1 */ + if (c == '#') { + add_chunk(ns,chunk,allow); + copy_location(s,chunk); + cpp_lines = 1; + state = 40; + } else if (isspace(c)) { + Putc(c,chunk); + skip_whitespace(s,chunk); + } else { + state = 1; + Ungetc(c,s); + } + break; + case 1: /* Non-preprocessor directive */ + /* Look for SWIG directives */ + if (c == '%') { + state = 100; + break; + } + Putc(c,chunk); + if (c == '\n') state = 0; + else if (c == '\"') { + start_line = Getline(s); + if (skip_tochar(s,'\"',chunk) < 0) { + cpp_error(Getfile(s),-1,"Unterminated string constant starting at line %d\n",start_line); + } + } else if (c == '\'') { + start_line = Getline(s); + if (skip_tochar(s,'\'',chunk) < 0) { + cpp_error(Getfile(s),-1,"Unterminated character constant starting at line %d\n",start_line); + } + } + else if (c == '/') state = 30; /* Comment */ + break; + + case 30: /* Possibly a comment string of some sort */ + start_line = Getline(s); + Putc(c,chunk); + if (c == '/') state = 31; + else if (c == '*') state = 32; + else state = 1; + break; + case 31: + Putc(c,chunk); + if (c == '\n') state = 0; + break; + case 32: + Putc(c,chunk); + if (c == '*') state = 33; + break; + case 33: + Putc(c,chunk); + if (c == '/') state = 1; + else if (c != '*') state = 32; + break; + + case 40: /* Start of a C preprocessor directive */ + if (c == ' ') state = 40; /* Strip off any leading white-space */ + else if (c == '\n') { + Putc('\n',chunk); + state = 0; + } else { + /* Got the start of a preprocessor directive */ + Ungetc(c,s); + Clear(id); + copy_location(s,id); + state = 41; + } + break; + + case 41: /* Build up the name of the preprocessor directive */ + if (isspace(c)) { + Clear(value); + Clear(comment); + if (c == '\n') { + Ungetc(c,s); + state = 50; + } + else state = 42; + copy_location(s,value); + break; + } + Putc(c,id); + break; + + case 42: /* Strip any leading space before preprocessor value */ + if (isspace(c)) { + if (c == '\n') { + Ungetc(c,s); + state = 50; + } + break; + } + state = 43; + /* no break intended here */ + + case 43: + /* Get preprocessor value */ + if (c == '\n') { + Ungetc(c,s); + state = 50; + } else if (c == '/') { + state = 45; + } else { + Putc(c,value); + if (c == '\\') state = 44; + } + break; + + case 44: + if (c == '\n') cpp_lines++; + Putc(c,value); + state = 43; + break; + + /* States 45-48 are used to remove, but retain comments from macro values. The comments + will be placed in the output in an alternative form */ + + case 45: + if (c == '/') state = 46; + else if (c == '*') state = 47; + else { + Putc('/',value); + Putc(c,value); + state = 43; + } + break; + case 46: + if (c == '\n') { + cpp_lines++; + state = 50; + } else Putc(c,comment); + break; + case 47: + if (c == '*') state = 48; + else Putc(c,comment); + break; + case 48: + if (c == '/') state = 43; + else if (c == '*') Putc(c,comment); + else { + Putc('*',comment); + Putc(c,comment); + state = 47; + } + break; + case 50: + /* Check for various preprocessor directives */ + String_chop(value); + if (Cmp(id,"define") == 0) { + if (allow) { + DOH *m, *v, *v1; + Seek(value,0,SEEK_SET); + m = SWIG_cpp_define(value,0); + if ((m) && !(Getattr(m,"args"))) { + v = Copy(Getattr(m,"value")); + if (Len(v)) { + silent_errors = 1; + v1 = swig_cpp_replace(v); + silent_errors = 0; + if (!check_id(v1)) { + if (Len(comment) == 0) + Printf(ns,"%%constant %s %s;\n", Getattr(m,"name"), v1); + else + Printf(ns,"%%constant %s %s; /*%s*/\n", Getattr(m,"name"),v1,comment); + cpp_lines--; + } + } + } + } + } else if (Cmp(id,"undef") == 0) { + if (allow) SWIG_cpp_undef(value); + } else if (Cmp(id,"ifdef") == 0) { + cond_lines[level] = Getline(id); + level++; + if (allow) { + start_level = level; + /* See if the identifier is in the hash table */ + if (!Getattr(symbols,value)) allow = 0; + mask = 1; + } + } else if (Cmp(id,"ifndef") == 0) { + cond_lines[level] = Getline(id); + level++; + if (allow) { + start_level = level; + /* See if the identifier is in the hash table */ + if (Getattr(symbols,value)) allow = 0; + mask = 1; + } + } else if (Cmp(id,"else") == 0) { + if (level == 0) { + cpp_error(Getfile(s),Getline(id),"Misplaced #else.\n"); + } else { + cond_lines[level-1] = Getline(id); + if (allow) { + allow = 0; + mask = 0; + } else if (level == start_level) allow = 1; + } + } else if (Cmp(id,"endif") == 0) { + level--; + if (level < 0) { + cpp_error(Getfile(id),Getline(id),"Extraneous #endif ignored.\n"); + level = 0; + } else { + if (level < start_level) allow = 1; + } + } else if (Cmp(id,"if") == 0) { + cond_lines[level] = Getline(id); + level++; + if (allow) { + start_level = level; + sval = swig_cpp_replace(value); + sval = Copy(value); + Seek(sval,0,SEEK_SET); + val = SWIG_expr(sval,&e); + if (e) { + Seek(value,0,SEEK_SET); + /* cpp_error(Getfile(value),Getline(value),"Could not evaluate '%s'\n", value); */ + allow = 0; + } else { + if (val == 0) + allow = 0; + } + mask = 1; + } + } else if (Cmp(id,"elif") == 0) { + if (level == 0) { + cpp_error(Getfile(s),Getline(id),"Misplaced #elif.\n"); + } else { + cond_lines[level-1] = Getline(id); + if (allow) { + allow = 0; + mask = 0; + } else if (level == start_level) { + sval = swig_cpp_replace(value); + Seek(sval,0,SEEK_SET); + val = SWIG_expr(sval,&e); + if (e) { + Seek(value,0,SEEK_SET); + /* cpp_error(Getfile(value),Getline(value),"Could not evaluate '%s'\n", value); */ + allow = 0; + } else { + if (val) + allow = 1*mask; + else + allow = 0; + } + } + } + } else if (Cmp(id,"line") == 0) { + } else if (Cmp(id,"include") == 0) { + if ((include_all) && (allow)) { + DOH *s1, *s2, *fn; + Seek(value,0,SEEK_SET); + fn = get_filename(value); + s1 = cpp_include(fn); + if (s1) { + Printf(ns,"%%include \"%s\" {\n", SWIG_last_file()); + s2 = SWIG_cpp_parse(s1); + addline(ns,s2,allow); + Printf(ns,"\n}\n"); + Delete(s2); + } + Delete(s1); + } + } else if (Cmp(id,"pragma") == 0) { + } else { + } + for (i = 0; i < cpp_lines; i++) + Putc('\n',ns); + state = 0; + break; + + /* Swig directives */ + case 100: + /* %{,%} block */ + if (c == '{') { + start_line = Getline(s); + add_chunk(ns,chunk,allow); + copy_location(s,chunk); + Putc('%',chunk); + Putc(c,chunk); + state = 105; + } + /* %#cpp - an embedded C preprocessor directive (we strip off the %) */ + else if (c == '#') { + Putc(c,chunk); + state = 0; + } else if (isidentifier(c)) { + Clear(decl); + Putc('%',decl); + Putc(c,decl); + state = 110; + } else { + Putc(c,chunk); + state = 1; + } + break; + + case 105: + Putc(c,chunk); + if (c == '%') + state = 106; + break; + + case 106: + Putc(c,chunk); + if (c == '}') { + state = 1; + addline(ns,chunk,allow); + Clear(chunk); + copy_location(s,chunk); + } else { + state = 105; + } + break; + + case 110: + if (!isidchar(c)) { + Ungetc(c,s); + /* Look for common Swig directives */ + if ((Cmp(decl,"%include") == 0) || (Cmp(decl,"%import") == 0) || (Cmp(decl,"%extern") == 0)) { + /* Got some kind of file inclusion directive */ + if (allow) { + DOH *s1, *s2, *fn; + fn = get_filename(s); + s1 = cpp_include(fn); + if (s1) { + add_chunk(ns,chunk,allow); + copy_location(s,chunk); + Printf(ns,"%s \"%s\" {\n", decl, SWIG_last_file()); + s2 = SWIG_cpp_parse(s1); + addline(ns,s2,allow); + Printf(ns,"\n}\n"); + Delete(s2); + Delete(s1); + } + Delete(fn); + } + state = 1; + } else if (Cmp(decl,"%line") == 0) { + /* Got a line directive */ + state = 1; + } else if (Cmp(decl,"%define") == 0) { + /* Got a define directive */ + add_chunk(ns,chunk,allow); + copy_location(s,chunk); + Clear(value); + copy_location(s,value); + state = 150; + } else { + Printf(chunk,"%s", decl); + state = 1; + } + } else { + Putc(c,decl); + } + break; + + /* Searching for the end of a %define statement */ + case 150: + Putc(c,value); + if (c == '%') { + int i = 0; + char *d = "enddef\n"; + for (i = 0; i < 7; i++) { + c = Getc(s); + Putc(c,value); + if (c != d[i]) break; + } + if (i == 7) { + /* Got the macro */ + for (i = 0; i < 8; i++) { + Delitem(value,DOH_END); + } + if (allow) { + Seek(value,0,SEEK_SET); + SWIG_cpp_define(value,1); + } + Putc('\n',ns); + addline(ns,value,0); + state = 0; + } + } + break; + default : + Printf(stderr,"cpp: Invalid parser state %d\n", state); + abort(); + break; + } + } + while (level > 0) { + cpp_error(Getfile(s),-1,"Missing #endif for conditional starting on line %d\n", cond_lines[level-1]); + level--; + } + if (state == 150) { + Seek(value,0,SEEK_SET); + cpp_error(Getfile(s),-1,"Missing %%enddef for macro starting on line %d\n",Getline(value)); + } + if ((state >= 105) && (state < 107)) { + cpp_error(Getfile(s),-1,"Unterminated %%{ ... %%} block starting on line %d\n", start_line); + } + if ((state >= 30) && (state < 40)) { + cpp_error(Getfile(s),-1,"Unterminated comment starting on line %d\n", start_line); + } + add_chunk(ns,chunk,allow); + copy_location(s,chunk); + + DelScope(scp); + return ns; +} + diff --git a/SWIG/Source/Preprocessor/expr.c b/SWIG/Source/Preprocessor/expr.c new file mode 100644 index 000000000..68fae2a95 --- /dev/null +++ b/SWIG/Source/Preprocessor/expr.c @@ -0,0 +1,325 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + +#include "swigcpp.h" + +/* ----------------------------------------------------------------------------- + * expr.c + * + * This is your basic ol' integer arithmetic expression evaluator. Could have + * used yacc for this, but it generates something like 1000 lines of code + * (whereas this implementation is much smaller). + * + * This module is primarily for use by the preprocessor and any other parts of + * the compiler that need to perform compile-time expression evaluation. + * ----------------------------------------------------------------------------- */ + +static Scanner *scan = 0; + +typedef struct { + int op; + long value; +} exprval; + +#define EXPR_TOP 1 +#define EXPR_VALUE 2 +#define EXPR_OP 3 +#define EXPR_GROUP 4 +#define EXPR_UMINUS 100 + +static exprval stack[256]; /* Parsing stack */ +static int sp = 0; /* Stack pointer */ +static int prec[256]; /* Precedence rules */ +static int expr_init = 0; /* Initialization flag */ +static char *errmsg = 0; /* Parsing error */ + +/* Initialize the precedence table for various operators. Low values have higher precedence */ +static void init_precedence() { + prec[TOKEN_NOT] = 10; + prec[EXPR_UMINUS] = 10; + prec[TOKEN_STAR] = 20; + prec[TOKEN_SLASH] = 20; + prec[TOKEN_PERCENT] = 20; + prec[TOKEN_PLUS] = 30; + prec[TOKEN_MINUS] = 30; + prec[TOKEN_LSHIFT] = 40; + prec[TOKEN_RSHIFT] = 40; + prec[TOKEN_AND] = 50; + prec[TOKEN_XOR] = 60; + prec[TOKEN_OR] = 70; + prec[TOKEN_EQUALTO] = 80; + prec[TOKEN_NOTEQUAL] = 80; + prec[TOKEN_LESSTHAN] = 80; + prec[TOKEN_GREATERTHAN] = 80; + prec[TOKEN_LTEQUAL] = 80; + prec[TOKEN_GTEQUAL] = 80; + prec[TOKEN_LNOT] = 90; + prec[TOKEN_LAND] = 100; + prec[TOKEN_LOR] = 110; + expr_init = 1; +} + +/* Reduce a single operator on the stack */ +static void reduce_op() { + if (stack[sp-1].op != EXPR_OP) { + errmsg = "Missing operator"; + sp = 0; + return; + } + switch(stack[sp-1].value) { + case TOKEN_STAR: + stack[sp-2].value = stack[sp-2].value * stack[sp].value; + sp -= 2; + break; + case TOKEN_EQUALTO: + stack[sp-2].value = stack[sp-2].value == stack[sp].value; + sp -= 2; + break; + case TOKEN_NOTEQUAL: + stack[sp-2].value = stack[sp-2].value != stack[sp].value; + sp -= 2; + break; + case TOKEN_PLUS: + stack[sp-2].value = stack[sp-2].value + stack[sp].value; + sp -= 2; + break; + case TOKEN_MINUS: + stack[sp-2].value = stack[sp-2].value - stack[sp].value; + sp -= 2; + break; + case TOKEN_AND: + stack[sp-2].value = stack[sp-2].value & stack[sp].value; + sp -= 2; + break; + case TOKEN_LAND: + stack[sp-2].value = stack[sp-2].value && stack[sp].value; + sp -= 2; + break; + case TOKEN_OR: + stack[sp-2].value = stack[sp-2].value | stack[sp].value; + sp -= 2; + break; + case TOKEN_LOR: + stack[sp-2].value = stack[sp-2].value || stack[sp].value; + sp -= 2; + break; + case TOKEN_XOR: + stack[sp-2].value = stack[sp-2].value ^ stack[sp].value; + sp -= 2; + break; + case TOKEN_LESSTHAN: + stack[sp-2].value = stack[sp-2].value < stack[sp].value; + sp -= 2; + break; + case TOKEN_GREATERTHAN: + stack[sp-2].value = stack[sp-2].value > stack[sp].value; + sp -= 2; + break; + case TOKEN_LTEQUAL: + stack[sp-2].value = stack[sp-2].value <= stack[sp].value; + sp -= 2; + break; + case TOKEN_GTEQUAL: + stack[sp-2].value = stack[sp-2].value >= stack[sp].value; + sp -= 2; + break; + case TOKEN_NOT: + stack[sp-1].value = ~stack[sp].value; + sp--; + break; + case TOKEN_LNOT: + stack[sp-1].value = !stack[sp].value; + sp--; + break; + case EXPR_UMINUS: + stack[sp-1].value = -stack[sp].value; + sp--; + break; + case TOKEN_SLASH: + stack[sp-2].value = stack[sp-2].value / stack[sp].value; + sp -= 2; + break; + case TOKEN_PERCENT: + stack[sp-2].value = stack[sp-2].value % stack[sp].value; + sp -= 2; + break; + case TOKEN_LSHIFT: + stack[sp-2].value = stack[sp-2].value << stack[sp].value; + sp -= 2; + break; + case TOKEN_RSHIFT: + stack[sp-2].value = stack[sp-2].value >> stack[sp].value; + sp -= 2; + break; + default: + errmsg = "Syntax error"; + sp = 0; + break; + } + stack[sp].op = EXPR_VALUE; +} + +/* ----------------------------------------------------------------------------- + * void SWIG_expr_init() + * + * Initialize the expression evaluator + * ----------------------------------------------------------------------------- */ + +void SWIG_expr_init() { + if (!expr_init) init_precedence(); + if (!scan) scan = NewScanner(); +} + +/* ----------------------------------------------------------------------------- + * int SWIG_expr(DOH *s, int *error) + * + * Evaluates an arithmetic expression in s. + * ----------------------------------------------------------------------------- */ + +int SWIG_expr(DOH *s, int *error) { + int token = 0; + int op = 0; + + sp = 0; + assert(s); + assert(scan); + + Seek(s,0,SEEK_SET); + *error = 0; + Scanner_clear(scan); + Scanner_push(scan,s); + + /* Put initial state onto the stack */ + stack[sp].op = EXPR_TOP; + stack[sp].value = 0; + + while (1) { + /* Look at the top of the stack */ + switch(stack[sp].op) { + case EXPR_TOP: + /* An expression. Can be a number or another expression enclosed in parens */ + token = Scanner_token(scan); + if (!token) { + errmsg = "Expected an expression"; + *error = 1; + return 0; + } + break; + case EXPR_VALUE: + /* A value is on the stack. We may reduce or evaluate depending on what the next token is */ + token = Scanner_token(scan); + if (!token) { + /* End of input. Might have to reduce if an operator is on stack */ + while (sp > 0) { + if (stack[sp-1].op == EXPR_OP) { + reduce_op(); + } else if (stack[sp-1].op == EXPR_GROUP) { + errmsg = "Missing \')\'"; + *error = 1; + return 0; + } else goto syntax_error; + } + return stack[sp].value; + } + /* Token must be an operator */ + switch(token) { + case TOKEN_STAR: + case TOKEN_EQUALTO: + case TOKEN_NOTEQUAL: + case TOKEN_PLUS: + case TOKEN_MINUS: + case TOKEN_AND: + case TOKEN_LAND: + case TOKEN_OR: + case TOKEN_LOR: + case TOKEN_XOR: + case TOKEN_LESSTHAN: + case TOKEN_GREATERTHAN: + case TOKEN_LTEQUAL: + case TOKEN_GTEQUAL: + case TOKEN_SLASH: + case TOKEN_PERCENT: + case TOKEN_LSHIFT: + case TOKEN_RSHIFT: + if ((sp == 0) || (stack[sp-1].op == EXPR_GROUP)) { + /* No possibility of reduce. Push operator and expression */ + sp++; + stack[sp].op = EXPR_OP; + stack[sp].value = token; + sp++; + stack[sp].op = EXPR_TOP; + stack[sp].value = 0; + } else { + if (stack[sp-1].op != EXPR_OP) goto syntax_error; + op = stack[sp-1].value; /* Previous operator */ + + /* Now, depending on the precedence relationship between the last operator and the current + we will reduce or push */ + + if (prec[op] <= prec[token]) { + /* Reduce the previous operator */ + reduce_op(); + if (stack[sp].op != EXPR_VALUE) goto syntax_error; + } + sp++; + stack[sp].op = EXPR_OP; + stack[sp].value = token; + sp++; + stack[sp].op = EXPR_TOP; + stack[sp].value = 0; + } + break; + case TOKEN_RPAREN: + if (sp == 0) goto extra_rparen; + + /* Might have to reduce operators first */ + while ((sp > 0) && (stack[sp-1].op == EXPR_OP)) reduce_op(); + if ((sp == 0) || (stack[sp-1].op != EXPR_GROUP)) goto extra_rparen; + stack[sp-1].op = EXPR_VALUE; + stack[sp-1].value = stack[sp].value; + sp--; + break; + default: + goto syntax_error; + break; + } + break; + default: + fprintf(stderr,"Internal error in expression evaluator.\n"); + abort(); + } + } + syntax_error: + errmsg = "Syntax error"; + *error = 1; + return 0; + + extra_rparen: + errmsg = "Extra \')\'"; + *error = 1; + return 0; +} + +/* Return the expression error message */ +char *SWIG_expr_error() { + return errmsg; +} + + + + + + + diff --git a/SWIG/Source/Preprocessor/swigcpp.h b/SWIG/Source/Preprocessor/swigcpp.h new file mode 100644 index 000000000..78fe65fca --- /dev/null +++ b/SWIG/Source/Preprocessor/swigcpp.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + +#ifndef _SWIGCPP_H +#define _SWIGCPP_H + +#include "swigcore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int SWIG_expr(DOH *s, int *error); +extern char *SWIG_expr_error(void); +extern void SWIG_expr_init(); + +extern DOH *SWIG_cpp_define(DOH *str, int swigmacro); +extern void SWIG_cpp_undef(DOH *name); +extern void SWIG_cpp_init(); +extern DOH *SWIG_cpp_parse(DOH *s); +extern void SWIG_cpp_include_all(int); + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/SWIG/Source/README b/SWIG/Source/README new file mode 100644 index 000000000..54b736050 --- /dev/null +++ b/SWIG/Source/README @@ -0,0 +1,17 @@ +SWIG Source Directory + +All new development is being done in C. Portions of the old SWIG1.1 +C++ base are slowly being converted over. + +DOH - Dave's Object Hack. A C library containing core datatypes + for most of the new C-based system. + +Core - C based SWIG core. + +Preprocessor - C based preprocessing module. + +SWIG1.1 - Old SWIG1.1 C++ core + +Modules1.1 - Old SWIG1.1 C++ modules + + diff --git a/SWIG/Source/SWIG1.1/Makefile.in b/SWIG/Source/SWIG1.1/Makefile.in new file mode 100644 index 000000000..7d245ea49 --- /dev/null +++ b/SWIG/Source/SWIG1.1/Makefile.in @@ -0,0 +1,105 @@ +####################################################################### +# $Header$ +# Simplified Wrapper and Interface Generator (SWIG) +# +# Makefile for version 1.0 Final +# Dave Beazley +# August 1, 1996 +# +# This makefile is now mostly constructed by ./configure. +# +# $Log$ +# Revision 1.1 2000/01/11 20:08:16 beazley +# First checkin +# +# Revision 1.2 1999/11/14 02:42:56 beazley +# Initial 1.3 checkin +# +# Revision 1.1.1.1 1999/02/28 02:00:51 beazley +# Swig1.1 +# +# Revision 1.1 1996/08/12 01:55:02 dmb +# Initial revision +# +####################################################################### + +#.KEEP_STATE: + + +srcdir = @srcdir@ +VPATH = @srcdir@ + +# Set your C++ compiler here. g++ works on most machines, +# but you might have to change it depending on your installation. +# +CC = @CXX@ + +# +# Set the prefix below to indicate where you want SWIG to install its +# files. Normally this is /usr/local +# + +prefix = @prefix@ + +# Location of the SWIG library. Is normally put in /usr/local/lib/swig_lib +# The SWIG library contains configuration files and library modules +# so you should install it someplace where it can be easily accessed. + +SWIG_LIB = $(prefix)/lib/swig1.3 + +# YACC parser. Use bison by default. if this doesn't work, switch +# it over to yacc. If that still doesn't work, let me know... + +YACC = @YACC@ + +# Comment out the following line if you're on an SGI or don't have ranlib! +RANLIB = @RANLIB@ +AR = @AR@ + +######################################################################## +# Normally, you shouldn't have to change anything below this point # +######################################################################## + +LIBOBJS = main.o scanner.o symbol.o include.o types.o parms.o emit.o newdoc.o ascii.o \ + html.o latex.o cplus.o lang.o hash.o sstring.o wrapfunc.o getopt.o comment.o \ + typemap.o naming.o + +LIBSRCS = main.cxx scanner.cxx symbol.cxx include.cxx types.cxx parms.cxx emit.cxx \ + newdoc.cxx ascii.cxx html.cxx latex.cxx cplus.cxx lang.cxx hash.cxx \ + sstring.cxx wrapfunc.cxx getopt.cxx comment.cxx typemap.cxx naming.cxx + +PARSER = parser.y +INCLUDE = -I../Include -I. -I../Core -I../Preprocessor -I../DOH/Include +CFLAGS = @CFLAGS@ -DSWIG_LIB='"$(SWIG_LIB)"' -DSWIG_CC='"$(CC)"' @DEFS@ +SHELL = /bin/sh + +# +# +# +# Rules for creation of a .o file from .cxx +.SUFFIXES: .cxx +.cxx.o: + $(CC) $(INCLUDE) $(CFLAGS) -c -o $*.o $< + +all: parser.o $(LIBOBJS) + +parser.o: parser.cxx $(LIBHEADERS) + $(CC) $(INCLUDE) $(CFLAGS) parser.cxx -c -o parser.o + +parser.cxx: $(PARSER) + $(YACC) @YACCFLAGS@ + @cp y.tab.h parser.h + @cp y.tab.c parser.cxx + +parser:: + @cp y.tab.c.bison parser.cxx + @cp y.tab.h.bison parser.h + @cp y.tab.h.bison y.tab.h + $(CC) $(CFLAGS) parser.cxx -c -o parser.o + +clean:: + rm -f *.o libswig.a y.tab.c y.tab.h + +nuke:: + rm -f Makefile *~ #* core a.out + diff --git a/SWIG/Source/SWIG1.1/ascii.cxx b/SWIG/Source/SWIG1.1/ascii.cxx new file mode 100644 index 000000000..9028d0b87 --- /dev/null +++ b/SWIG/Source/SWIG1.1/ascii.cxx @@ -0,0 +1,464 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "swig.h" +#include "ascii.h" +#include + +/******************************************************************************* + * $Header$ + * + * File : ascii.cxx + * + * Module for producing ASCII documentation. + * + *******************************************************************************/ + +// ----------------------------------------------------------------------------- +// ASCII::ASCII() +// +// Constructor. Initializes the ASCII module. +// +// Inputs : None +// +// Output : Documentation module object +// +// Side Effects : +// Sets page-width and indentation. +// ----------------------------------------------------------------------------- + +ASCII::ASCII() { + sect_count = 0; + indent = 8; + columns = 70; +} + +// ----------------------------------------------------------------------------- +// void ASCII::print_string(char *s, int margin, int mode) +// +// Prints a string to the documentation file. Performs line wrapping and +// other formatting. +// +// Inputs : +// s = NULL terminate ASCII string +// margin = Number of characters to be inserted on left side +// mode = If set, text will be reformatted. Otherwise, it's +// printed verbatim (with indentation). +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void ASCII::print_string(char *s, int margin, int mode) { + + char *c; + int i; + int lbreak = 0; + int col; + + c = s; + + if (!s) return; + // Apply indentation + + for (i = 0; i < margin; i++) + fputc(' ',f_doc); + + col = margin; + if (mode) { + + // Dump out text in formatted mode + + // Strip leading white-space + + while ((*c) && (isspace(*c))) { + c++; + } + while (*c) { + switch(*c) { + case '\n': + case '\\': + if (lbreak) { + col = margin; + fputc('\n',f_doc); + for (i = 0; i < margin; i++) + fputc(' ',f_doc); + lbreak = 0; + } else { + if ((*c) == '\n') { + col++; + } + lbreak++; + } + break; + case ' ': + case '\t': + case '\r': + case '\f': + if (col > columns) { + fputc('\n',f_doc); + for (i = 0; i < margin; i++) + fputc(' ',f_doc); + col = margin; + } else { + fputc(' ',f_doc); + col++; + } + // Skip over rest of white space found + while ((*c) && isspace(*c)) c++; + c--; + lbreak = 0; + break; + default : + if (lbreak) fputc(' ',f_doc); + lbreak = 0; + fputc(*c,f_doc); + col++; + break; + } + c++; + } + } else { + // Dump out text in pre-formatted mode + while (*c) { + switch(*c) { + case '\n': + fputc('\n',f_doc); + for (i = 0; i < margin; i++) + fputc(' ',f_doc); + break; + default : + fputc(*c,f_doc); + col++; + break; + } + c++; + } + } +} + +// ----------------------------------------------------------------------------- +// void ASCII::print_decl(DocEntry *de) +// +// Prints the documentation entry corresponding to a declaration +// +// Inputs : +// de = Documentation entry (which should be for a declaration) +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void ASCII::print_decl(DocEntry *de) { + + int i; + char *c; + + c = de->usage.get(); + fprintf(f_doc,"%s\n",c); + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + for (i = 0; i < indent; i++) + fputc(' ',f_doc); + fprintf(f_doc,"[ "); + print_string(c,0,1); + fprintf(f_doc," ]\n"); + } + } + + c = de->text.get(); + if (strlen(c) > 0) { + print_string(c,indent,de->format); + fprintf(f_doc,"\n"); + if (de->format) fputc('\n',f_doc); + } else { + fprintf(f_doc,"\n"); + } +} + +// ----------------------------------------------------------------------------- +// void ASCII::print_text(DocEntry *de) +// +// Prints the documentation for a block of text. Will strip any leading white +// space from the text block. +// +// Inputs : +// de = Documentation entry of text +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void ASCII::print_text(DocEntry *de) { + char *c; + c = de->text.get(); + if (strlen(c) > 0) { + while ((*c == '\n')) c++; + print_string(c,0,de->format); + fprintf(f_doc,"\n\n"); + } +} + +// ----------------------------------------------------------------------------- +// void ASCII::title(DocEntry *de) +// +// Sets the title of the documentation file. +// +// Inputs : +// de = Documentation entry of the title. +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void ASCII::title(DocEntry *de) { + char *c; + + c = de->usage.get(); + if (strlen(c) > 0) { + fprintf(f_doc,"%s\n\n",c); + } + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + fprintf(f_doc,"[ "); + print_string(c,0,1); + fprintf(f_doc," ]\n"); + } + } + + c = de->text.get(); + if (strlen(c)) { + print_string(c,0,de->format); + } + fprintf(f_doc,"\n\n"); +} + +// ----------------------------------------------------------------------------- +// void ASCII::newsection(DocEntry *de, int sectnum) +// +// Starts a new section. Will underline major sections and subsections, but +// not minor subsections. +// +// Inputs : +// de = Documentation entry of the section +// sectnum = Section number. +// +// Output : None +// +// Side Effects : +// Forces a new subsection to be created within the ASCII module. +// ----------------------------------------------------------------------------- + +void ASCII::newsection(DocEntry *de,int sectnum) { + int i,len = 0; + char temp[256]; + char *c; + + sect_num[sect_count] = sectnum; + sect_count++; + for (i = 0; i < sect_count; i++) { + sprintf(temp,"%d.",sect_num[i]); + fprintf(f_doc,"%s",temp); + len += strlen(temp); + } + c = de->usage.get(); + fprintf(f_doc," %s\n", c); + len += strlen(c) + 2; + + // Print an underline if this is a major category + + if (sect_count <= 1) { + for (i = 0; i < len; i++) + fputc('=',f_doc); + fputc('\n',f_doc); + } else if (sect_count == 2) { + for (i = 0; i < len; i++) + fputc('-',f_doc); + fputc('\n',f_doc); + } else { + fputc('\n',f_doc); + } + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + fprintf(f_doc,"[ "); + print_string(c,0,1); + fprintf(f_doc," ]\n\n"); + } + } + + // If there is a description text. Print it + + c = de->text.get(); + if (strlen(c) > 0) { + print_string(c,0,de->format); + fprintf(f_doc,"\n"); + } + fprintf(f_doc,"\n"); +} + +// ----------------------------------------------------------------------------- +// void ASCII::endsection() +// +// Ends the current section. It is an error to call this without having first +// called newsection(). +// +// Inputs : None +// +// Output : None +// +// Side Effects : +// Pops out of the current section, moving back into the parent section +// ----------------------------------------------------------------------------- + +void ASCII::endsection() { + if (sect_count > 0) sect_count--; +} + +// ----------------------------------------------------------------------------- +// void ASCII::separator() +// +// Prints a small dashed line that is used to designate the end of C++ class +// subsections. +// +// Inputs : None +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void ASCII::separator() { + int i; + for (i = 0; i < 10; i++) + fputc('-',f_doc); + fprintf(f_doc,"\n\n"); +} + +// ----------------------------------------------------------------------------- +// void ASCII::init(char *filename) +// +// Initializes the documentation module and opens up the documentation file. +// +// Inputs : filename = name of documentation file (without suffix) +// +// Output : None +// +// Side Effects : Opens the documentation file. +// ----------------------------------------------------------------------------- + +void ASCII::init(char *filename) { + char f[256]; + + sprintf(f,"%s.doc",filename); + sprintf(fn,"%s",filename); + f_doc = fopen(f,"w"); + if (f_doc == NULL) { + fprintf(stderr, "Unable to open %s\n", fn); + SWIG_exit(1); + } + +} + +// ----------------------------------------------------------------------------- +// void ASCII::close() +// +// Closes the documentation module. This function should only be called once +// +// Inputs : None +// +// Output : None +// +// Side Effects : Closes the documentation file. +// ----------------------------------------------------------------------------- + +void ASCII::close(void) { + + fclose(f_doc); + if (Verbose) + fprintf(stderr,"Documentation written to %s.doc\n", fn); + +} + +// ----------------------------------------------------------------------------- +// void ASCII::style(char *name, char *value) +// +// Looks for style parameters that the user might have supplied using the +// %style directive. Unrecognized options are simply ignored. +// +// Inputs : +// name = name of the style parameter +// value = value of the style parameter (optional) +// +// Output : None +// +// Side Effects : Can change internal settings of 'indent' and 'columns' members. +// ----------------------------------------------------------------------------- + +void ASCII::style(char *name, char *value) { + if (strcmp(name,"ascii_indent") == 0) { + if (value) { + indent = atoi(value); + } + } else if (strcmp(name,"ascii_columns") == 0) { + if (value) { + columns = atoi(value); + } + } +} + +// ----------------------------------------------------------------------------- +// void ASCII::parse_args(int argc, char **argv) +// +// Function for processing options supplied on the SWIG command line. +// +// Inputs : +// argc = Number of arguments +// argv = Argument strings +// +// Output : None +// +// Side Effects : May set various internal parameters. +// ----------------------------------------------------------------------------- + +static char *ascii_usage = "\ +ASCII Documentation Options (available with -dascii)\n\ + None available.\n\n"; + +void ASCII::parse_args(int argc, char **argv) { + int i; + + for (i = 0; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-help") == 0) { + fputs(ascii_usage,stderr); + } + } + } +} + + diff --git a/SWIG/Source/SWIG1.1/ascii.h b/SWIG/Source/SWIG1.1/ascii.h new file mode 100644 index 000000000..05794b621 --- /dev/null +++ b/SWIG/Source/SWIG1.1/ascii.h @@ -0,0 +1,64 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * ascii.h + * + * ASCII specific functions for producing documentation. Basically + * prints things out as 80 column ASCII. + ***********************************************************************/ + +class ASCII : public Documentation { +private: + FILE *f_doc; + char fn[256]; + void print_string(char *s,int indent,int mode); + int indent; // Indentation (for formatting) + int columns; // Number of columns (for formatting) + int sect_count; // Section counter + int sect_num[20]; // Section numbers + // Style parameters +public: + ASCII(); + void parse_args(int argc, char **argv); + void title(DocEntry *de); + void newsection(DocEntry *de, int sectnum); + void endsection(); + void print_decl(DocEntry *de); + void print_text(DocEntry *de); + void separator(); + void init(char *filename); + void close(void); + void style(char *name, char *value); +}; + + + + + + + + + + + + + + + + + + diff --git a/SWIG/Source/SWIG1.1/comment.cxx b/SWIG/Source/SWIG1.1/comment.cxx new file mode 100644 index 000000000..5aade8c17 --- /dev/null +++ b/SWIG/Source/SWIG1.1/comment.cxx @@ -0,0 +1,697 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" + +/******************************************************************************* + * $Header$ + * + * File : comment.cxx + * + * This is a semi-magical module for associating C/C++ comments with + * documentation entries. While this sounds like it might be easy, + * there are a number of subtle problems getting things to associate + * correctly. + * + * Here's the general idea : + * + * 1. The parser and scanner feed both C comments and documentation + * entries to this class. These may show up in really bizarre + * orders (not necessarily the order seen in an interface file). + * + * 2. We maintain separate lists of comments and documentation + * entries. + * + * 3. Periodically, we go through the list of documentation entries + * and see if we can associate any comments. + * + * 4. Upon completion of parsing, it's critical that we cleanup + * the lists using the cleanup() method. + * + *******************************************************************************/ + +// ----------------------------------------------------------------------------- +// struct Comment +// +// Structure used to maintain a linked list of comments for later use. +// ----------------------------------------------------------------------------- + +class Comment { +public: + String *text; // Text of the comment + int first_line; // First line of the comment + int last_line; // Last line of the comment + int column; // First column of comment + char *file; // Name of the file that it was in + Comment *next; // Next comment (when in a linked list) + Comment *prev; // Previous comment + static Comment *comment_list; // List of all comments + + Comment(char *t, int line, int col, char *f); + ~Comment(); + static Comment *find(DocEntry *de, CommentHandler *ch); + void attach(DocEntry *de, CommentHandler *ch); +}; + + +// ----------------------------------------------------------------------- +// Create a new comment. Automatically puts it on the linked list +// ----------------------------------------------------------------------- +Comment::Comment(char *t, int line, int col, char *f) { + int nlines = 0; + char *c; + + text = new String(t); + c = t; + while (*c) { + if (*c == '\n') nlines++; + c++; + } + first_line = line; + column = col; + last_line = line + nlines - 1; + file = copy_string(f); + if (comment_list) { + comment_list->prev = this; + } + next = comment_list; + comment_list = this; + prev = 0; +} + +// ----------------------------------------------------------------------- +// Destroy a comment +// ----------------------------------------------------------------------- +Comment::~Comment() { + delete text; + delete file; + // Remove from linked list (if applicable) + if (prev) { + prev->next = next; + } + if (next) { + next->prev = prev; + } + if (this == comment_list) comment_list = next; +} +// ----------------------------------------------------------------------- +// find(DocEntry *de, CommentHandler *ch) +// +// This function tries to a find a comment matching the search criteria +// of a given comment handler and documentation entry. +// ----------------------------------------------------------------------- + +Comment *Comment::find(DocEntry *de, CommentHandler *ch) { + Comment *c; + + c = comment_list; + + // Start walking down our list of stored comments + + while (c) { + // printf("Searching %x : %s\n", c, c->text->get()); + if (strcmp(de->file,c->file) == 0) { + + // At least comment is in the right file. Now check line numbers + + if (ch->location == BEFORE) { + + // Check to see if the last line of the comment is close + // enough to our declaration. + + if ((c->last_line <= de->line_number) && + ((de->line_number - c->last_line) <= ch->skip_lines)) { + return c; + } + } else { // AFTER mode + // Check to see if the first line of the comment is close + // enough to our declaration. + + if ((c->first_line >= de->end_line) && + ((c->first_line - de->end_line) <= ch->skip_lines)) { + return c; + } + } + // Check to see if the line numbers are too small. Comments + // are processed in order so there's no sense in checking + // all entries. + + if (c->last_line < de->line_number) + return 0; + + } + c = c->next; + } + return 0; +} + +// ----------------------------------------------------------------------- +// void attach(DocEntry *de, CommentHandler *ch) +// +// This function attachs a comment to a documentation entry and applies +// all of the style information in the comment handler. +// ----------------------------------------------------------------------- +void Comment::attach(DocEntry *de, CommentHandler *ch) { + int nlines = 0; + char **split = 0; + char *c; + int i,lnum,el; + if (!de) return; + + // If we're ignoring comments, forget it + if (ch->ignore) { + return; + } + + // If the comment is formatted, no style processing is applied + + if (de->format) { + de->text << *text; + return; + } + + // Untabify the comment + + if (ch->untabify) text->untabify(); + + // Count how many lines we have + + c = text->get(); + while (*c) { + if (*c == '\n') nlines++; + c++; + } + + if (nlines == 0) return; + + // Tokenize the documentation string into lines + + split = new char*[nlines+1]; + c = text->get(); + i = 0; + split[i] = c; + while (*c) { + if (*c == '\n') { + *(c++) = 0; + split[++i] = c; + } else c++; + } + lnum = 0; + + // Now process the chop_top and chop_bottom values + // if nlines < (chop_top + chop_bottom), then we do nothing + + if (nlines > (ch->chop_top + ch->chop_bottom)) { + lnum += ch->chop_top; + el = nlines-ch->chop_bottom; + } else { + el = nlines; + } + + // Now process in-between lines + + while (lnum < el) { + /* Chop line */ + if (split[lnum]) { + if (strlen(split[lnum]) > (unsigned) (ch->chop_left+ch->chop_right)) { + if (ch->chop_right > 0) + split[lnum][strlen(split[lnum]) - ch->chop_right] = 0; + de->text << &split[lnum][ch->chop_left]; + } + } + lnum++; + de->text << "\n"; + } + + // printf("*** ATTACHING %s : %s\n", de->usage.get(), de->text.get()); + delete split; +} + + +CommentHandler *comment_handler = 0; +Comment *Comment::comment_list = 0; + +// ------------------------------------------------------------------------ +// struct DocEntryList +// +// This structure manages a linked list of documentation entries that +// haven't had comments attached to them yet. +// +// As a general rule, this list tends to remain rather short. +// ------------------------------------------------------------------------ + +struct DocEntryList { + DocEntry *de; + CommentHandler *ch; + DocEntryList *next; + DocEntryList *prev; + static DocEntryList *doc_list; + + // ----------------------------------------------------------------------- + // Create a new list entry + // ----------------------------------------------------------------------- + DocEntryList(DocEntry *d, CommentHandler *c) { + + de = d; + ch = c; + next = doc_list; + prev = 0; + if (doc_list) + doc_list->prev = this; + doc_list = this; + + // Only allow a few doc entries to survive + + if (this->next) { + if (this->next->next) { + delete this->next->next; + } + } + } + + // ----------------------------------------------------------------------- + // Destroy a list entry + // ----------------------------------------------------------------------- + ~DocEntryList() { + if (prev) { + prev->next = next; + } + if (next) { + next->prev = prev; + } + if (this == doc_list) doc_list = next; + }; + + // ----------------------------------------------------------------------- + // static check() + // + // Checks the list of documentation entries to see if any can be associated. + // ----------------------------------------------------------------------- + + static void check() { + + DocEntryList *dl, *dl_temp; + Comment *cmt; + + // printf ("Checking\n"); + dl = doc_list; + while (dl) { + cmt = Comment::find(dl->de,dl->ch); + if (cmt) { + // Okay, we found a matching comment. Attach it to this + // documentation entry. + cmt->attach(dl->de,dl->ch); + + // Destroy the comment and doc list entry + delete cmt; + + // Declarations are always coming in order so we're going + // to blow away all of them past this point + + dl_temp = dl->next; + delete dl; + dl = dl_temp; + } else { + dl = dl->next; + } + } + } +}; + + +DocEntryList *DocEntryList::doc_list = 0; + +// ----------------------------------------------------------------------------- +// CommentHandler::CommentHandler() +// +// Constructor. Creates a new comment handler. Sets up some default values +// for comment handling. +// +// Inputs : None +// +// Output : New CommentHandler object. +// +// Side Effects : Sets default comment handling parameters. +// ----------------------------------------------------------------------------- + +CommentHandler::CommentHandler() { + skip_lines = 1; + location = AFTER; + chop_top = 0; + chop_bottom = 0; + chop_left = 3; + chop_right = 0; + untabify = 1; + ignore = 0; +} + +// ----------------------------------------------------------------------------- +// CommentHandler::CommentHandler(CommentHandler *c) +// +// Constructor. Creates a new comment handler, but copies attributes from +// another handler. +// +// Inputs : +// c = A different comment handler. +// +// Output : A new CommentHandler object. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +CommentHandler::CommentHandler(CommentHandler *c) { + skip_lines = c->skip_lines; + location = c->location; + chop_top = c->chop_top; + chop_bottom = c->chop_bottom; + chop_left = c->chop_left; + chop_right = c->chop_right; + untabify = c->untabify; + ignore = c->ignore; +} + +// ----------------------------------------------------------------------------- +// CommentHandler::~CommentHandler() +// +// Destructor. Destroys a comment handler. Does nothing interesting at the +// moment. +// +// Inputs : None +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +CommentHandler::~CommentHandler() { +} + +// ----------------------------------------------------------------------------- +// void CommentHandler::add_comment(char *text, int line_num, int col, char *file) +// +// This function takes a character string as comment text and appends +// it to the current comment string (which is held in Comment::comment_list) +// +// 1. If two comments appear in successive lines, they are +// concatenated. This is to handle C++ style comments like the +// one surrounding this text. +// +// 2. If a new comment appears, we simply create a new one +// +// Inputs : +// text = Text of the comment +// line_num = Starting line number of the comment +// col = Starting column of the comment +// file = File in which the comment was located. +// +// Output : None +// +// Side Effects : +// Saves the comment in an internal linked list. +// If multiple comments appear in succession, some may end up +// in our comment list permanently (ie. never attached to any +// particular declaration). +// ----------------------------------------------------------------------------- + +void CommentHandler::add_comment(char *text, int line_num, int col, char *file) { + + char *c; + int nlines = 0; + Comment *cmt; + + // printf("line_num = %d, %s\n", line_num,text); + + // Count up how many lines are in this comment + + c = text; + while (*c) { + if (*c == '\n') nlines++; + c++; + } + + // Check to see if this comment is in a successive line to the last one + + cmt = Comment::comment_list; + + if (cmt) { + + // Check for column alignment + if ((cmt->column == col) && (line_num == (cmt->last_line + 1)) && + (nlines <= 1)) { + *(cmt->text) << text; + cmt->last_line = line_num + nlines - 1; + } else { + // This is a new comment, add it to our list + cmt = new Comment(text,line_num,col,file); + } + } else { + cmt = new Comment(text,line_num,col,file); + } +} + +// ----------------------------------------------------------------------------- +// void CommentHanlder::set_entry(DocEntry *d) +// +// This grabs a DocEntry and hangs onto it. +// +// We will place the doc entry into our documentation list and then +// check it to see if any comments are sitting around. +// +// Inputs : d = Documentation Entry +// +// Output : None +// +// Side Effects : +// May attach comments to the documentation entry. In this case, +// comments and DocEntries may be removed from internal lists. +// ----------------------------------------------------------------------------- + +void CommentHandler::set_entry(DocEntry *d) { + + // printf("Set entry : file: %s, line %d, %s\n", d->file, d->line_number, d->usage.get()); + + // Create a new list entry and save it + + new DocEntryList(d,this); + + // Check all of the documentation entries to see if they can be placed + + DocEntryList::check(); + +} + +// ----------------------------------------------------------------------------- +// static void CommentHandler::cleanup() +// +// Checks all documentation entries and sees if there are any comments available. +// If so, they are attached. This function is usually only called upon completion +// of parsing. +// +// Inputs : None +// +// Output : None +// +// Side Effects : +// Removes documentation entries and comments from internal lists. +// +// ----------------------------------------------------------------------------- + +void CommentHandler::cleanup() { + int nc, nd; + Comment *c; + DocEntryList *d; + + DocEntryList::check(); + + // Figure out how bad we're doing on memory + + nc = 0; + nd = 0; + c = Comment::comment_list; + while (c) { + nc++; + c = c->next; + } + + d = DocEntryList::doc_list; + while(d) { + nd++; + d = d->next; + } + + if (Verbose) { + printf("%d unprocessed comments, %d unprocessed doc entries.\n",nc,nd); + } +} + +// ----------------------------------------------------------------------------- +// void CommentHandler::style(char *name, char *value) +// +// Processes comment handling style parameters. The following parameters +// are available : +// +// after - Comments appear after a declaration +// before - Comments appear before a declaration +// skip - Number of blank lines between comment and decl. +// chop_top - Number of lines to chop from top of a comment +// chop_bottom - Number of lines to chop from bottom of a comment +// chop_left - Number of characters to chop from left +// chop_right - Number of characters to chop from right +// tabify - Leave tabs in comment text +// untabify - Strip tabs and convert them into spaces. +// ignore - Ignore comments +// enable - Enable comments +// +// Inputs : +// name - Name of style parameter +// value - Optional parameter value +// +// Output : None +// +// Side Effects : Changes style of comment handler object. +// +// ----------------------------------------------------------------------------- + +void CommentHandler::style(char *name, char *value) { + + if (strcmp(name,"before") == 0) { + location = BEFORE; + } else if (strcmp(name,"after") == 0) { + location = AFTER; + } else if (strcmp(name,"skip") == 0) { + if (value) + skip_lines = atoi(value); + } else if (strcmp(name,"chop_top") == 0) { + if (value) + chop_top = atoi(value); + } else if (strcmp(name,"chop_bottom") == 0) { + if (value) + chop_bottom = atoi(value); + } else if (strcmp(name,"chop_left") == 0) { + if (value) + chop_left = atoi(value); + } else if (strcmp(name,"chop_right") == 0) { + if (value) + chop_right = atoi(value); + } else if (strcmp(name,"tabify") == 0) { + untabify = 0; + } else if (strcmp(name,"untabify") == 0) { + untabify = 1; + } else if (strcmp(name,"ignore") == 0) { + ignore = 1; + } else if (strcmp(name,"enable") == 0) { + ignore = 0; + } +} + +// ----------------------------------------------------------------------------- +// void CommentHandler::parse_args(int argc, char **argv) +// +// Function for processing command line options given on the SWIG command line. +// See the help string below for available options. +// +// Inputs : +// argc = Argument count +// argv = Argument strings +// +// Output : None +// +// Side Effects : +// Changes various style parameters for the top-level CommentHandler. +// ----------------------------------------------------------------------------- + +static char *comment_usage = "\ +Comment Style Options : \n\ + -Safter - Use comments after a declaration.\n\ + -Sbefore - Use comments before a declaration.\n\ + -Schop_bottom n - Chop n lines from bottom of comments.\n\ + -Schop_left n - Chop n characters from left of a comment.\n\ + -Schop_right n - Chop n characters from right of a comment.\n\ + -Schop_top n - Chop n lines from top of comments.\n\ + -Signore - Ignore comments.\n\ + -Sskip n - Max lines between comment and declaration.\n\ + -Stabify - Do not convert tabs.\n\ + -Suntabify - Convert tabs into spaces (the default).\n\n"; + +void CommentHandler::parse_args(int argc, char **argv) { + int i; + + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-Sbefore") == 0) { + this->style("before",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Safter") == 0) { + this->style("after",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Schop_top") == 0) { + if (argv[i+1]) { + this->style("chop_top",argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-Schop_bottom") == 0) { + if (argv[i+1]) { + this->style("chop_bottom",argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-Schop_left") == 0) { + if (argv[i+1]) { + this->style("chop_left",argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-Schop_right") == 0) { + if (argv[i+1]) { + this->style("chop_right",argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-Sskip") == 0) { + if (argv[i+1]) { + this->style("skip",argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-Suntabify") == 0) { + this->style("untabify",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Stabify") == 0) { + this->style("tabify",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Signore") == 0) { + this->style("ignore",0); + } else if (strcmp(argv[i],"-help") == 0) { + fputs(comment_usage,stderr); + } + } + } +} diff --git a/SWIG/Source/SWIG1.1/cplus.cxx b/SWIG/Source/SWIG1.1/cplus.cxx new file mode 100644 index 000000000..d28036a5a --- /dev/null +++ b/SWIG/Source/SWIG1.1/cplus.cxx @@ -0,0 +1,2681 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" + +/******************************************************************************* + * $Header$ + * + * File : cplus.cxx + * + * This module defines parser entry points for supporting C++. Primarily + * this module is in charge of keeping track of the contents of C++ classes, + * organizing inheritance, and other things. + * + * Eventually this module will be merged with the type handling mechanism + * in SWIG 2.0 so it's a little messy right now. + * + * General comments : + * + * 1. The words "simple" and "C++" are rarely used in the same + * sentence. Therefore this module is going to be some sort + * of compromise. + * + * 2. I'm using the "Annotated C++ Reference Manual" (ARM) as my + * reference for handling certain cases. Of course, there + * is a high probability that I have misinterpreted or overlooked + * certain cases. + * + * 3. It is not my intent to write a full C++ compiler. + * + * My goals are simple : + * - Support simple ANSI C-like class member functions and data. + * - Support constructors and destructors. + * - static member functions. + * - basic inheritance. + * - virtual functions. + * - References + * + * I do not plan to support the following anytime in the near future + * - Operator overloading + * - templates + * + * Caution : + * + * The control flow in this module is completely insane. But here's the + * rough outline. + * + * Stage 1 : SWIG Parsing + * cplus_open_class() - Open up a new class + * cplus_* - Add members to class + * cplus_inherit() - Inherit from base classes + * cplus_class_close() - Close class + * + * ... + * cplus_open_class() + * ... + * cplus_class_close() + * + * ... and so on, until the end of the file + * + * After stage 1, all classes have been read, but nothing has been + * sent to the language module yet. + * + * Stage 2 : Code generation + * For each class we've saved, do this : + * lang->cpp_open_class() - Open class + * lang->cpp_* - Emit members + * lang->cpp_inherit() - Inherit + * lang->cpp_close_class() - Close class + * + * This two-stage approach solves a number of problems related to working + * with multiple files, mutually referenced classes, add adding methods. + * Just keep in mind that all C++ code is emitted *after* an entire SWIG + * file has been parsed. + * + * Improved code generation and inheritance of added methods (2/18/97): + * + * Each C++ declaration now has an associated function name attached to it. + * For example : + * + * class Foo { + * void bar(); + * } + * + * Generates a member function "bar()" with a accessor function named + * "Foo_bar()". We will use this recorded accessor function to generate + * better code for inheritance. For example : + * + * class Foo2 : public Foo { + * + * ... + * } + * + * Will create a function called "Foo2_bar()" that is really mapped + * onto the base-class method "Foo_bar()". This should improve + * code generation substantially. + * + * Tricky stuff : + * - Each target language is responsible for naming wrapper + * functions. + * + *******************************************************************************/ + +// Some status variables + +static int Inherit_mode = 0; // Set if we're inheriting members +static char *ccode = 0; // Set to optional C code (if available) +static Hash *localtypes; // Localtype hash +static int abstract =0; // Status bit set during code generation + +static int cpp_id = 0; + +// Forward references + +void cplus_member_func(char *, char *, DataType *, ParmList *, int); +void cplus_constructor(char *, char *, ParmList *); +void cplus_destructor(char *, char *); +void cplus_variable(char *, char *, DataType *); +void cplus_static_func(char *, char *, DataType *, ParmList *); +void cplus_declare_const(char *, char *, DataType *, char *); +void cplus_static_var(char *, char *, DataType *); +void cplus_inherit_decl(char **); + +// ----------------------------------------------------------------------------- +// void add_local_type(char *type, char *classname) +// void add_local_type(DataType *type, char *classname) +// +// Adds a new datatype to the local datatype hash. This is used to handle +// datatypes defined within a class. +// +// Inputs : Datatype to place in hash +// +// Output : None +// +// Side Effects : Updates localtypes hash. +// ----------------------------------------------------------------------------- + +static void add_local_type(char *type, char *classname) { + String str; + + if (!localtypes) return; // No hash table initialized, ignore this + + str << classname << "::" << type; + localtypes->add(type,copy_string(str)); +} + +void add_local_type(DataType *type, char *classname) { + add_local_type(type->name,classname); +} + +// ----------------------------------------------------------------------------- +// void update_local_type(DataType *type) +// +// Checks to see whether this datatype is part of a class definition. If so, +// we update the type-name by appending the class prefix to it. Uses the +// name stored in current_class unless unavailable. +// +// Inputs : type = Datatype +// +// Output : type is updated with a new name. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +static void update_local_type(DataType *type) { + + char *newname = 0; + + // Lookup the datatype in the hash table + + if (!localtypes) return; + + newname = (char *) localtypes->lookup(type->name); + if (newname) { + strcpy(type->name, newname); + } +} + +// ----------------------------------------------------------------------------- +// void update_parms(ParmList *l) +// +// Updates all of the parameters in a parameter list with the proper C++ prefix +// (if neccessary). +// +// Inputs : l = Parameter list +// +// Output : Parameter list l is updated (make sure its a copy!) +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +static void update_parms(ParmList *l) { + Parm *p; + p = l->get_first(); + while (p) { + update_local_type(p->t); + + // Check for default arguments + + if ((p->defvalue) && (localtypes)) { + char *s; + s = (char *) localtypes->lookup(p->defvalue); + if (s) { + delete p->defvalue; + p->defvalue = copy_string(s); + } + } + p = l->get_next(); + } +} + +// ----------------------------------------------------------------------- +// class CPP_member +// +// Base class for various kinds of C++ members +// ----------------------------------------------------------------------- +class CPP_member { +public: + char *name; // Name of the member + char *iname; // Name of member in the interpreter + int is_static; // Is this a static member? + int new_method; // Is this a new method (added by SWIG)? + int line; // What line number was this member on + char *file; // What file was this in? + char *code; // Was there any supplied code? + char *base; // Base class where this was defined + int inherited; // Was this member inherited? + DocEntry *de; // Documentation entry + CPP_member *next; // Next member (for building linked lists) + int id; // type id when created + + virtual void inherit(int) { }; // Inheritance rule (optional) + virtual void emit() = 0; // Emit rule +}; + +// ---------------------------------------------------------------------- +// class CPP_function : public CPP_member +// +// Structure for handling a C++ member function +// ---------------------------------------------------------------------- + +class CPP_function : public CPP_member { +public: + DataType *ret_type; + ParmList *parms; + int new_object; + int is_virtual; + + CPP_function(char *n, char *i, DataType *t, ParmList *l, int s, int v = 0) { + name = copy_string(n); + iname = copy_string(i); + ret_type = new DataType(t); + parms = new ParmList(l); + is_static = s; + is_virtual = v; + new_method = AddMethods; + new_object = NewObject; + inherited = Inherit_mode; + de = 0; + next = 0; + line = line_number; + file = input_file; + if (Inherit_mode) { + id = cpp_id; + } else { + id = type_id; + } + if (AddMethods) { + if (strlen(CCode.get())) + code = copy_string(CCode.get()); + else + code = 0; + } else { + code = 0; + } + } + void inherit(int mode) { + doc_entry = 0; // No documentation for an inherited member + if (mode & INHERIT_FUNC) { + // Set up the proper addmethods mode and provide C code (if provided) + int oldaddmethods = AddMethods; + int oldnewobject = NewObject; + AddMethods = new_method; + NewObject = new_object; + CCode = code; + if (is_static) { + cplus_static_func(name, iname, ret_type, parms); + } else { + cplus_member_func(name, iname, ret_type, parms, is_virtual); + } + AddMethods = oldaddmethods; + NewObject = oldnewobject; + CCode = ""; + } + } + void emit() { + ParmList *l; + DataType *t; + AddMethods = new_method; + NewObject = new_object; + doc_entry = de; // Restore documentation entry + line_number = line; // Restore line and file + input_file = file; + ccode = code; + + // Make a copy of the parameter list and upgrade its types + + l = new ParmList(parms); + t = new DataType(ret_type); + update_parms(l); + update_local_type(t); + if (is_static) { + lang->cpp_static_func(name, iname, t, l); + } else { + lang->cpp_member_func(name, iname, t, l); + } + l->check_defined(); + t->check_defined(); + delete l; + delete t; + } +}; + +// -------------------------------------------------------------------------- +// class CPP_constructor : public CPP_member +// +// Class for holding a C++ constructor definition. +// -------------------------------------------------------------------------- + +class CPP_constructor : public CPP_member { +public: + ParmList *parms; + CPP_constructor(char *n, char *i, ParmList *l) { + name = copy_string(n); + iname = copy_string(i); + parms = new ParmList(l); + new_method = AddMethods; + inherited = 0; + de = 0; + next = 0; + line = line_number; + file = input_file; + id = type_id; + if (AddMethods) { + if (strlen(CCode.get())) + code = copy_string(CCode.get()); + else + code = 0; + } else { + code = 0; + } + } + void emit() { + if (1) { + ParmList *l; + AddMethods = new_method; + doc_entry = de; + line_number = line; + input_file = file; + ccode = code; + + // Make a copy of the parameter list and upgrade its types + + l = new ParmList(parms); + update_parms(l); + lang->cpp_constructor(name,iname,l); + l->check_defined(); + delete l; + } else { + if (Verbose) { + fprintf(stderr,"%s:%d: Constructor for abstract base class ignored.\n", + file,line); + } + } + } +}; + + +// -------------------------------------------------------------------------- +// class CPP_destructor : public CPP_member +// +// Class for holding a destructor definition +// -------------------------------------------------------------------------- + +class CPP_destructor : public CPP_member { +public: + + CPP_destructor(char *n, char *i) { + name = copy_string(n); + iname = copy_string(i); + new_method = AddMethods; + de = 0; + next = 0; + inherited = 0; + line = line_number; + file = input_file; + id = type_id; + if (AddMethods) { + if (strlen(CCode.get())) + code = copy_string(CCode.get()); + else + code = 0; + } else { + code = 0; + } + + } + void emit() { + AddMethods = new_method; + doc_entry = de; + line_number = line; + input_file = file; + ccode = code; + lang->cpp_destructor(name, iname); + } +}; + +// ------------------------------------------------------------------------- +// class CPP_variable : public CPP_member +// +// Class for a managing a data member +// ------------------------------------------------------------------------- + +class CPP_variable : public CPP_member { +public: + DataType *type; + int status; + CPP_variable(char *n, char *i, DataType *t, int s) { + name = copy_string(n); + iname = copy_string(i); + type = new DataType(t); + is_static = s; + status = Status; + de = 0; + next = 0; + new_method = AddMethods; + line = line_number; + file = input_file; + if (Inherit_mode) { + id = cpp_id; + } else { + id = type_id; + } + code = 0; + inherited = 0; + } + + // Emit code for this + + void emit() { + DataType *t; + int old_status = Status; + doc_entry = de; + AddMethods = new_method; + Status = status; + line_number = line; + input_file = file; + ccode = code; + + t = new DataType(type); + if (t->qualifier) { + // if (strcmp(t->qualifier,"const") == 0) Status = Status | STAT_READONLY; + } + update_local_type(t); + if (!is_static) { + lang->cpp_variable(name,iname,t); + } else { + lang->cpp_static_var(name,iname,t); + } + t->check_defined(); + Status = old_status; + delete t; + } + + // Inherit into another class + + void inherit(int mode) { + int oldstatus = Status; + Status = status; + doc_entry = 0; + if (mode & INHERIT_VAR) { + if (!is_static) { + int oldaddmethods = AddMethods; + AddMethods = new_method; + CCode = code; + cplus_variable(name,iname,type); + AddMethods = oldaddmethods; + CCode = ""; + } else { + cplus_static_var(name,iname,type); + } + } + Status = oldstatus; + } +}; + +// ------------------------------------------------------------------------- +// class CPP_constant : public CPP_member +// +// Class for managing constant values +// ------------------------------------------------------------------------- + +class CPP_constant : public CPP_member { +public: + char *value; + DataType *type; + CPP_constant(char *n, char *i, DataType *t, char *v) { + name = copy_string(n); + iname = copy_string(i); + type = new DataType(t); + value = copy_string(v); + de = 0; + new_method = AddMethods; + next = 0; + line = line_number; + file = input_file; + if (Inherit_mode) + id = cpp_id; + else + id = type_id; + code = 0; + inherited = 0; + } + + void emit() { + doc_entry = de; + AddMethods = new_method; + line_number = line; + input_file = file; + ccode = code; + lang->cpp_declare_const(name,iname,type,value); + type->check_defined(); + } + + void inherit(int mode) { + doc_entry = 0; + if (mode & INHERIT_CONST) + cplus_declare_const(name, iname, type, value); + } +}; + +// ---------------------------------------------------------------------- +// class CPP_class +// +// Class for managing class members (internally) +// ---------------------------------------------------------------------- + +static char *inherit_base_class = 0; + +class CPP_class { +public: + char *classname; // Real class name + char *classrename; // New name of class (if applicable) + char *classtype; // class type (struct, union, class) + int strip; // Strip off class declarator + int wextern; // Value of extern wrapper variable for this class + int have_constructor; // Status bit indicating if we've seen a constructor + int have_destructor; // Status bit indicating if a destructor has been seen + int is_abstract; // Status bit indicating if this is an abstract class + int generate_default; // Generate default constructors + int objective_c; // Set if this is an objective C class + int error; // Set if this class can't be generated + int line; // Line number + char **baseclass; // Base classes (if any) + Hash *local; // Hash table for local types + Hash *scope; // Local scope hash table + DocEntry *de; // Documentation entry of class + CPP_member *members; // Linked list of members + CPP_class *next; // Next class + static CPP_class *classlist; // List of all classes stored + Pragma *pragmas; // Class pragmas + + CPP_class(char *name, char *ctype) { + CPP_class *c; + classname = copy_string(name); + classtype = copy_string(ctype); + classrename = 0; + baseclass = 0; + de = doc_entry; + local = new Hash; // Create hash table for storing local datatypes + scope = 0; + error = 0; + pragmas = 0; + line = line_number; + + // Walk down class list and add to end + + c = classlist; + if (c) { + while (c->next) { + c = c->next; + } + c->next = this; + } else { + classlist = this; + } + next = 0; + members = 0; + strip = 0; + wextern = WrapExtern; + have_constructor = 0; + have_destructor = 0; + is_abstract = 0; + generate_default = GenerateDefault; + objective_c = ObjCClass; + } + + // ------------------------------------------------------------------------------ + // Add a new C++ member to this class + // ------------------------------------------------------------------------------ + + void add_member(CPP_member *m) { + CPP_member *cm; + + // Set base class where this was defined + if (inherit_base_class) + m->base = inherit_base_class; + else + m->base = classname; + if (!members) { + members = m; + return; + } + cm = members; + while (cm->next) { + cm = cm->next; + } + cm->next = m; + } + // ------------------------------------------------------------------------------ + // Search for a member with the given name. Returns the member on success, 0 on failure + // ------------------------------------------------------------------------------ + + CPP_member *search_member(char *name) { + CPP_member *m; + char *c; + m = members; + while (m) { + c = m->iname ? m->iname : m->name; + if (strcmp(c,name) == 0) return m; + m = m->next; + } + return 0; + } + + // ------------------------------------------------------------------------------ + // Inherit. Put all the declarations associated with this class into the current + // ------------------------------------------------------------------------------ + + void inherit_decls(int mode) { + CPP_member *m; + m = members; + while (m) { + inherit_base_class = m->base; + cpp_id = m->id; + m->inherit(mode); + m = m->next; + } + inherit_base_class = 0; + } + + // ------------------------------------------------------------------------------ + // Emit all of the declarations associated with this class + // ------------------------------------------------------------------------------ + + void emit_decls() { + CPP_member *m = members; + int last_scope = name_scope(0); + abstract = is_abstract; + while (m) { + cpp_id = m->id; + name_scope(cpp_id); // Set proper naming scope + m->emit(); + m = m->next; + } + name_scope(last_scope); + } + + // ------------------------------------------------------------------------------ + // Search for a given class in the list + // ------------------------------------------------------------------------------ + + static CPP_class *search(char *name) { + CPP_class *c; + c = classlist; + if (!name) return 0; + while (c) { + if (strcmp(name,c->classname) == 0) return c; + c = c->next; + } + return 0; + } + + // ------------------------------------------------------------------------------ + // Add default constructors and destructors + // + // ------------------------------------------------------------------------------ + + void create_default() { + if (!generate_default) return; + + // Try to generate a constructor if not available. + CCode = ""; + AddMethods = 0; + if ((!have_constructor) && (1)) { + ParmList *l; + l = new ParmList(); + doc_entry = new DocDecl(classname,this->de); + cplus_constructor(classname,0,l); + }; + + if (!have_destructor) { + doc_entry = new DocDecl(classname,this->de); + cplus_destructor(classname,0); + } + } + + // ------------------------------------------------------------------------------ + // Dump *all* of the classes saved out to the various + // language modules (this does what cplus_close_class used to do) + // ------------------------------------------------------------------------------ + static void create_all(); +}; + +CPP_class *CPP_class::classlist = 0; +static CPP_class *current_class; + +void CPP_class::create_all() { + CPP_class *c; + c = classlist; + while (c) { + if (!c->error) { + current_class = c; + localtypes = c->local; + if ((!c->wextern) && (c->classtype)) { + ObjCClass = c->objective_c; + doc_entry = c->de; + lang->cpp_open_class(c->classname,c->classrename,c->classtype,c->strip); + lang->cpp_pragma(c->pragmas); + c->create_default(); + if (c->baseclass) + cplus_inherit_decl(c->baseclass); + c->emit_decls(); + doc_entry = c->de; + lang->cpp_close_class(); + } + } + c = c->next; + } +} + +// ----------------------------------------------------------------------------- +// char *cplus_base_class(char *name) +// +// Given a member name, return the base class that it belongs to. +// ----------------------------------------------------------------------------- + +char *cplus_base_class(char *name) { + CPP_member *m = current_class->search_member(name); + if (m) { + return m->base; + } + return 0; +} + +// ----------------------------------------------------------------------------- +// void cplus_open_class(char *name, char *rname, char *ctype) +// +// Opens up a new C++ class. If rname is given, we'll be renaming the +// class. This also sets up some basic type equivalence for the +// type checker. +// +// Inputs : +// name = Name of the class +// rname = New name of the class (using %name() directive) +// ctype = Class type ("class","struct", or "union") +// +// Output : None +// +// Side Effects : +// Creates a new class obect internally. +// Added type-mappings to the SWIG type-checker module. +// Sets a number of internal state variables for later use. +// +// ----------------------------------------------------------------------------- + +void cplus_open_class(char *name, char *rname, char *ctype) { + + extern void typeeq_derived(char *, char *, char *cast=0); + char temp[256]; + CPP_class *c; + + // Add some symbol table management here + + // Search for a previous class definition + + c = CPP_class::search(name); + if (c) { + if (c->classtype) { + // Hmmm. We already seem to have defined this class so we'll + // create a new class object for whatever reason + current_class = new CPP_class(name, ctype); + } else { + // Looks like a reference was made to this class earlier + // somehow, but no other information is known. We'll + // make it our current class and fix it up a bit + current_class = c; + c->classtype = copy_string(ctype); + } + } else { + // Create a new class + current_class = new CPP_class(name, ctype); + current_class->de = doc_entry; + } + + // Set localtypes hash to our current class + + localtypes = current_class->local; + + // If renaming the class, set the new name + + if (rname) { + current_class->classrename = copy_string(rname); + } + + // Make a typedef for both long and short versions of this datatype + + if (name) { + if (strlen(name)) { + if (strlen(ctype) > 0) { + sprintf(temp,"%s %s", ctype, name); + typeeq_derived(temp,name); // Map "struct foo" to "foo" + typeeq_derived(name,temp); // Map "foo" to "struct foo" + } + } + } + + AddMethods = 0; // Reset add methods flag + +} + +// ----------------------------------------------------------------------------- +// DocEntry *cplus_set_class(char *name) +// +// This function sets the current class to a given name. If the class +// doesn't exist, this function will create one. If it already exists, +// we'll just use that. +// +// This function is used primarily to add or manipulate an already +// existing class, but in a different location. For example : +// +// %include "class.h" // Grab some classes +// ... +// %addmethods MyClass { // Add some members for shadow classes +// ... members ... +// } +// +// Sounds weird, but returns the documentation entry to class if it exists. +// The parser needs this so we can generate documentation correctly. +// +// Inputs : name = Name of the class +// +// Output : Documentation entry of class or NULL if it doesn't exist. +// The parser needs the documentation entry to properly associate +// new members. +// +// Side Effects : +// Changes the current class object. Resets a number of internal +// state variables. Should not be called inside of a open class +// declaration. +// ----------------------------------------------------------------------------- + +DocEntry *cplus_set_class(char *name) { + + CPP_class *c; + + // Look for a previous class definition + + c = CPP_class::search(name); + if (c) { + current_class = c; + localtypes = c->local; + return c->de; + } else { + fprintf(stderr,"%s:%d: Warning class %s undefined.\n",input_file,line_number,name); + current_class = new CPP_class(name,0); + localtypes = current_class->local; + return 0; + } +}; + +// This function closes a class open with cplus_set_class() + +void cplus_unset_class() { + current_class = 0; +} + +// ----------------------------------------------------------------------------- +// void cplus_class_close(char *name) +// +// Close a C++ class definition. Up to this point, we've only been collecting +// member definitions. This function merely closes the class object and +// stores it in a list. All classes are dumped after processing has completed. +// +// If name is non-null, it means that the name of the class has actually been +// set after all of the definitions. For example : +// +// typedef struct { +// double x,y,z +// } Vector; +// +// If this is the case, we'll use that as our classname and datatype. +// Otherwise, we'll just go with the classname and classtype set earlier. +// +// Inputs : name = optional "new name" for the class. +// +// Output : None +// +// Side Effects : Resets internal variables. Saves class in internal list. +// Registers the class with the language module, but doesn't +// emit any code. +// ----------------------------------------------------------------------------- + +void cplus_class_close(char *name) { + + if (name) { + // The name of our class suddenly changed by typedef. Fix things up + current_class->classname = copy_string(name); + + // This flag indicates that the class needs to have it's type stripped off + current_class->strip = 1; + } + + // If we're in C++ or Objective-C mode. We're going to drop the class specifier + + if ((CPlusPlus) || (ObjCClass)) { + current_class->strip = 1; + } + + // Register our class with the target language module, but otherwise + // don't do anything yet. + + char *iname; + if (current_class->classrename) iname = current_class->classrename; + else iname = current_class->classname; + + lang->cpp_class_decl(current_class->classname, iname, current_class->classtype); + + // Clear current class variable and reset + current_class = 0; + localtypes = 0; + +} + +// ----------------------------------------------------------------------------- +// void cplus_abort(void) +// +// Voids the current class--some kind of unrecoverable parsing error occurred. +// ----------------------------------------------------------------------------- + +void cplus_abort(void) { + current_class->error = 1; + current_class = 0; + localtypes = 0; +} + +// ----------------------------------------------------------------------------- +// void cplus_cleanup(void) +// +// This function is called after all parsing has been completed. It dumps all +// of the stored classes out to the language module. +// +// Inputs : None +// +// Output : None +// +// Side Effects : Emits all C++ wrapper code. +// ----------------------------------------------------------------------------- + +void cplus_cleanup(void) { + + // Dump all classes created at once (yikes!) + + CPP_class::create_all(); + lang->cpp_cleanup(); +} + +// ----------------------------------------------------------------------------- +// void cplus_inherit(int count, char **baseclass) +// +// Inherit from a baseclass. This function only really registers +// the inheritance, but doesn't do anything with it yet. +// +// Inputs : baseclass = A NULL terminated array of strings with the names +// of baseclasses. For multiple inheritance, there +// will be multiple entries in this list. +// +// Output : None +// +// Side Effects : Sets the baseclass variable of the current class. +// ----------------------------------------------------------------------------- + +void cplus_inherit(int count, char **baseclass) { + int i; + + // printf("Inheriting : count = %d, baseclass = %x\n",count,baseclass); + // If there are baseclasses, make copy of them + if (count) { + current_class->baseclass = (char **) new char*[count+1]; + for (i = 0; i < count; i++) + current_class->baseclass[i] = copy_string(baseclass[i]); + current_class->baseclass[i] = 0; + } else { + baseclass = 0; + } +} + +// ----------------------------------------------------------------------------- +// cplus_generate_types(char **baseclass) +// +// Generates the type-mappings between the current class and any associated +// base classes. This is done by performing a depth first search of the +// class hierarchy. Functions for performing correct type-casting are +// generated for each base-derived class pair. +// +// Inputs : baseclass = NULL terminated list of base classes +// +// Output : None +// +// Side Effects : Emits pointer conversion functions. Registers type-mappings +// with the type checking module. +// +// ----------------------------------------------------------------------------- + +static Hash convert; // Hash table of conversion functions + +void cplus_generate_types(char **baseclass) { + CPP_class *bc; + int i; + String cfunc, temp1, temp2, temp3; + extern void typeeq_derived(char *, char *, char *); + + if (!baseclass) { + return; + } + + // Generate type-conversion functions and type-equivalence + + i = 0; + while(baseclass[i]) { + cfunc = ""; + + bc = CPP_class::search(baseclass[i]); + if (bc) { + // Generate a conversion function (but only for C++) + + if (!current_class->objective_c) { + temp3 = ""; + temp3 << "Swig" << current_class->classname << "To" << bc->classname; + + if (convert.add(temp3,(void *) 1) != -1) { + + // Write a function for casting derived type to parent class + + cfunc << "static void *Swig" << current_class->classname << "To" << bc->classname + << "(void *ptr) {\n" + << tab4 << current_class->classname << " *src;\n" + << tab4 << bc->classname << " *dest;\n" + << tab4 << "src = (" << current_class->classname << " *) ptr;\n" + << tab4 << "dest = (" << bc->classname << " *) src;\n" + // << tab4 << "printf(\"casting...\\n\");\n" + << tab4 << "return (void *) dest;\n" + << "}\n"; + + fprintf(f_wrappers,"%s\n",cfunc.get()); + } + } else { + temp3 = "0"; + } + + // Make a type-equivalence allowing derived classes to be used in functions of the + + if (strlen(current_class->classtype) > 0) { + temp1 = ""; + temp1 << current_class->classtype << " " << current_class->classname; + temp2 = ""; + temp2 << bc->classtype << " " << bc->classname; + // Add various equivalences to the pointer table + + typeeq_derived(bc->classname, current_class->classname,temp3.get()); + typeeq_derived(temp2.get(), current_class->classname,temp3.get()); + typeeq_derived(temp2.get(), temp1.get(),temp3.get()); + typeeq_derived(bc->classname, temp1.get(),temp3.get()); + } else { + typeeq_derived(bc->classname, current_class->classname,temp3.get()); + } + // Now traverse the hierarchy some more + cplus_generate_types(bc->baseclass); + } + i++; + } +} + +// ----------------------------------------------------------------------------- +// void cplus_inherit_decl(char **baseclass) +// +// This function is called internally to handle inheritance between classes. +// Basically, we're going to generate type-checking information and call +// out to the target language to handle the inheritance. +// +// This function is only called when emitting classes to the language modules +// (after all parsing has been complete). +// +// Inputs : baseclass = NULL terminated list of base-class names. +// +// Output : None +// +// Side Effects : Generates type-mappings. Calls the language-specific +// inheritance function. +// ----------------------------------------------------------------------------- + +void cplus_inherit_decl(char **baseclass) { + + // If not base-classes, bail out + + if (!baseclass) return; + + Inherit_mode = 1; + lang->cpp_inherit(baseclass); // Pass inheritance onto the various languages + Inherit_mode = 0; + + // Create type-information for class hierarchy + + cplus_generate_types(baseclass); +} +// ----------------------------------------------------------------------------- +// void cplus_inherit_members(char *baseclass, int mode) +// +// Inherits members from a class. This is called by specific language modules +// to bring in members from base classes. It may or may not be called. +// +// This function is called with a *single* base-class, not multiple classes +// like other functions. To do multiple inheritance, simply call this +// with each of the associated base classes. +// +// Inputs : +// baseclass = Name of baseclass +// mode = Inheritance handling flags +// INHERIT_FUNC - Import functions in base class +// INHERIT_VAR - Import variables in base class +// INHERIT_CONST - Inherit constants +// INHERIT_ALL - Inherit everything (grossly inefficient) +// +// Output : None +// +// Side Effects : Imports methods from base-classes into derived classes. +// +// ----------------------------------------------------------------------------- + +void cplus_inherit_members(char *baseclass, int mode) { + CPP_class *bc; + + bc = CPP_class::search(baseclass); + if (bc) { + bc->inherit_decls(mode); + } else { + fprintf(stderr,"%s:%d: Warning. Base class %s undefined (ignored).\n", input_file, current_class->line, baseclass); + } +} + +// ----------------------------------------------------------------------------- +// void cplus_member_func(char *name, char *iname, DataType *type, ParmList *, is_virtual) +// +// Parser entry point to creating a C++ member function. This function primarily +// just records the function and does a few symbol table checks. +// +// Inputs : +// name = Real name of the member function +// iname = Renamed version (may be NULL) +// type = Return datatype +// l = Parameter list +// is_virtual = Set if this is a pure virtual function (ignored) +// +// Output : None +// +// Side Effects : +// Adds member function to current class. +// ----------------------------------------------------------------------------- + +void cplus_member_func(char *name, char *iname, DataType *type, ParmList *l, + int is_virtual) { + + CPP_function *f; + char *temp_iname; + + // First, figure out if we're renaming this function or not + + if (!iname) + temp_iname = name; + else + temp_iname = iname; + + // If we're in inherit mode, we need to check for duplicates. + // Issue a warning. + + if (Inherit_mode) { + if (current_class->search_member(temp_iname)) { + return; + } + } + + // Add it to our C++ class list + + f = new CPP_function(name,temp_iname,type,l,0,is_virtual); + f->de = doc_entry; + current_class->add_member(f); + + // If this is a pure virtual function, the class is abstract + + if (is_virtual) + current_class->is_abstract = 1; + +} + +// ----------------------------------------------------------------------------- +// void cplus_constructor(char *name, char *iname, ParmList *l) +// +// Parser entry point for creating a constructor. +// +// Inputs : +// name = Real name of the constructor (usually the same as the class) +// iname = Renamed version (may be NULL) +// l = Parameter list +// +// Output : None +// +// Side Effects : +// Adds a constructor to the current class. +// ----------------------------------------------------------------------------- + +void cplus_constructor(char *name, char *iname, ParmList *l) { + + CPP_constructor *c; + + // May want to check the naming scheme here + + c = new CPP_constructor(name,iname,l); + c->de = doc_entry; + current_class->add_member(c); + current_class->have_constructor = 1; + +} + +// ----------------------------------------------------------------------------- +// void cplus_destructor(char *name, char *iname) +// +// Parser entry point for adding a destructor. +// +// Inputs : +// name = Real name of the destructor (usually same as class name) +// iname = Renamed version (may be NULL) +// +// Output : None +// +// Side Effects : +// Adds a destructor to the current class +// +// ----------------------------------------------------------------------------- + +void cplus_destructor(char *name, char *iname) { + + CPP_destructor *d; + + d = new CPP_destructor(name,iname); + d->de = doc_entry; + current_class->add_member(d); + current_class->have_destructor = 1; +} + +// ----------------------------------------------------------------------------- +// void cplus_variable(char *name, char *iname, DataType *t) +// +// Parser entry point for creating a new member variable. +// +// Inputs : +// name = name of the variable +// iname = Renamed version (may be NULL) +// t = Datatype +// +// Output : None +// +// Side Effects : +// Adds a member variable to the current class +// ----------------------------------------------------------------------------- + +void cplus_variable(char *name, char *iname, DataType *t) { + + CPP_variable *v; + char *temp_iname; + + // If we're in inherit mode, we need to check for duplicates. + + if (iname) + temp_iname = iname; + else + temp_iname = name; + + if (Inherit_mode) { + if (current_class->search_member(temp_iname)) { + return; + } + } + + v = new CPP_variable(name,iname,t,0); + v->de = doc_entry; + current_class->add_member(v); +} + +// ----------------------------------------------------------------------------- +// void cplus_static_func(char *name, char *iname, DataType *type, ParmList *l) +// +// Parser entry point for creating a new static member function. +// +// Inputs : +// name = Real name of the function +// iname = Renamed version (may be NULL) +// type = Return datatype +// l = Parameter list +// +// Output : None +// +// Side Effects : +// Adds a static function to the current class. +// +// ----------------------------------------------------------------------------- + +void cplus_static_func(char *name, char *iname, DataType *type, ParmList *l) { + + char *temp_iname; + + // If we're in inherit mode, we need to check for duplicates. + + if (iname) temp_iname = iname; + else temp_iname = name; + + if (Inherit_mode) { + if (current_class->search_member(iname)) { + // Have a duplication + return; + } + } + + CPP_function *f = new CPP_function(name, temp_iname, type, l, 1); + f->de = doc_entry; + current_class->add_member(f); +} + +// ----------------------------------------------------------------------------- +// void cplus_declare_const(char *name, char *iname, DataType *type, char *value) +// +// Parser entry point for creating a C++ constant (usually contained in an +// enum). +// +// Inputs : +// name = Real name of the constant +// iname = Renamed constant (may be NULL) +// type = Datatype of the constant +// value = String representation of the value +// +// Output : None +// +// Side Effects : +// Adds a constant to the current class. +// ----------------------------------------------------------------------------- + +void cplus_declare_const(char *name, char *iname, DataType *type, char *value) { + + char *temp_iname; + + if (iname) temp_iname = iname; + else temp_iname = name; + + // If we're in inherit mode, we need to check for duplicates. + // Possibly issue a warning or perhaps a remapping + + if (Inherit_mode) { + if (current_class->search_member(temp_iname)) { + return; + } + } + + CPP_constant *c = new CPP_constant(name, temp_iname, type, value); + c->de = doc_entry; + current_class->add_member(c); + + // Update this symbol in the symbol table + update_symbol(name, type, value); + + // Add this symbol to local scope of a class + add_local_type(name, current_class->classname); +} + +// ----------------------------------------------------------------------------- +// void cplus_static_var(char *name, char *iname, DataType *type) +// +// Parser entry point for adding a static variable +// +// Inputs : +// name = Name of the member +// iname = Renamed version (may be NULL) +// type = Datatype +// +// Output : None +// +// Side Effects : +// Adds a static variable to the current class. +// ----------------------------------------------------------------------------- + +void cplus_static_var(char *name, char *iname, DataType *type) { + + char *temp_iname; + + if (iname) temp_iname = iname; + else temp_iname = name; + + // If we're in inherit mode, we need to check for duplicates. + // Possibly issue a warning or perhaps a remapping + + if (Inherit_mode) { + if (current_class->search_member(temp_iname)) { + return; + } + } + + CPP_variable *v = new CPP_variable(name, temp_iname, type, 1); + v->de = doc_entry; + current_class->add_member(v); +} + +// ----------------------------------------------------------------------------- +// cplus_add_pragma(char *lang, char *name, char *value) +// +// Add a pragma to a class +// ----------------------------------------------------------------------------- + +void cplus_add_pragma(char *lang, char *name, char *value) +{ + Pragma *pp; + Pragma *p = new Pragma; + p->filename = input_file; + p->lineno = line_number; + p->lang = lang; + p->name = name; + p->value = value; + + if (!current_class->pragmas) { + current_class->pragmas = p; + return; + } + pp = current_class->pragmas; + while (pp->next) { + pp = pp->next; + } + pp->next = p; +} + +// ------------------------------------------------------------------------------ +// C++/Objective-C code generation functions +// +// The following functions are responsible for generating the wrapper functions +// for C++ and Objective-C methods and variables. These functions are usually +// called by specific language modules, but individual language modules can +// choose to do something else. +// +// The C++ module sets a number of internal state variables before emitting various +// pieces of code. These variables are often checked implicitly by these +// procedures even though nothing is passed on the command line. +// +// The code generator tries to be somewhat intelligent about what its doing. +// The member_hash Hash table keeps track of wrapped members and is used for +// sharing code between base and derived classes. +// ----------------------------------------------------------------------------- + +static Hash member_hash; // Hash wrapping member function wrappers to scripting wrappers + +// ----------------------------------------------------------------------------- +// void cplus_emit_member_func(char *classname, char *classtype, char *classrename, +// char *mname, char *mrename, DataType *type, +// ParmList *l, int mode) +// +// This is a generic function to produce a C wrapper around a C++ member function. +// This function does the following : +// +// 1. Create a C wrapper function +// 2. Wrap the C wrapper function like a normal C function in SWIG +// 3. Add the function to the scripting language +// 4. Fill in the documentation entry +// +// Specific languages can choose to provide a different mechanism, but this +// function is used to provide a low-level C++ interface. +// +// The mode variable determines whether to create a new function or only to +// add it to the interpreter. This is used to support the %addmethods directive +// +// mode = 0 : Create a wrapper and add it (the normal mode) +// mode = 1 : Assume wrapper was already made and add it to the +// interpreter (%addmethods mode) +// +// Wrapper functions are usually created as follows : +// +// class Foo { +// int bar(args) +// } +// +// becomes .... +// Foo_bar(Foo *obj, args) { +// obj->bar(args); +// } +// +// if %addmethods mode is set AND there is supporting C code detected, make +// a function from it. The object is always called 'obj'. +// +// Then we wrap Foo_bar(). The name "Foo_bar" is actually contained in the parameter +// cname. This is so language modules can provide their own names (possibly for +// function overloading). +// +// This function makes no internal checks of the SWIG symbol table. This is +// up to the caller. +// +// Objective-C support (added 5/24/97) : +// +// If the class member function is part of an objective-C interface, everything +// works the same except that we change the calling mechanism to issue an +// Objective-C message. +// +// Optimizations (added 12/31/97) : +// +// For automatically generated wrapper functions. We now generate macros such +// as +// #define Foo_bar(a,b,c) (a->bar(b,c)) +// +// This should make the wrappers a little faster as well as reducing the amount +// of wrapper code. +// +// Inputs : +// classname = Name of C++ class +// classtype = Type of class (struct, union, class) +// classrename = Renamed class (if any) +// mname = Member name +// mrename = Renamed member +// type = Return type of the function +// l = Parameter list +// mode = addmethods mode +// +// Output : None +// +// Side Effects : +// Creates C accessor function in the wrapper file. +// Calls the language module to create a wrapper function. +// ----------------------------------------------------------------------------- + +void cplus_emit_member_func(char *classname, char *classtype, char *classrename, + char *mname, char *mrename, DataType *type, ParmList *l, + int mode) { + Parm *p; + ParmList *newparms; + int i; + String wrap; + String cname,iname; + String key; + String argname; + char *prefix; + char *prev_wrap = 0; + char *temp_mname; + + cname = ""; + iname = ""; + key = ""; + + // First generate a proper name for the member function + + // Get the base class of this member + if (!mrename) temp_mname = mname; + else temp_mname = mrename; + + char *bc = cplus_base_class(temp_mname); + if (!bc) bc = classname; + if (strlen(bc) == 0) bc = classname; + + // Generate the name of the C wrapper function (is always the same, regardless + // of renaming). + + cname << name_member(mname,bc); + + // Generate the scripting name of this function + if (classrename) + prefix = classrename; + else + prefix = classname; + + if (mrename) + iname << name_member(mrename,prefix); + else + iname << name_member(mname,prefix); + + // Now check to see if we have already wrapped a function like this. + // If so, we'll just use the existing wrapper. + + key << cname << "+"; + l->print_types(key); + // printf("key = %s\n", (char *) key); + char *temp = copy_string(iname); + if ((member_hash.add(key,temp)) == -1) { + delete [] temp; + prev_wrap = (char *) member_hash.lookup(key); + } + + // Only generate code if an already existing wrapper doesn't exist + + if (!prev_wrap) { + + // If mode = 0: Then we go ahead and create a wrapper macro + + if (!mode) { + cname = ""; + cname << iname; + wrap << "#define " << cname << "(_swigobj"; + + // Walk down the parameter list and Spit out arguments + + i = 0; + p = l->get_first(); + while (p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + wrap << ",_swigarg" << i; + i++; + } + p = l->get_next(); + } + + wrap << ") ("; + + if (!ObjCClass) { + wrap << "_swigobj->" << mname << "("; // C++ invocation + } else { + wrap << "[ _swigobj " << mname; // Objective C invocation + } + i = 0; + p = l->get_first(); + while(p != 0) { + if (ObjCClass) wrap << " " << p->objc_separator; + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + wrap << "_swigarg" << i; + i++; + } + p = l->get_next(); + if ((p != 0) && (!ObjCClass)) + wrap << ","; + } + if (!ObjCClass) + wrap << "))\n"; + else + wrap << "])\n"; + + // Emit it + fprintf(f_wrappers,"%s",wrap.get()); + } else { + if (ccode) { + wrap << "static "; + if (type->is_reference) { + type->is_pointer--; + } + wrap << type->print_full(); + if (type->is_reference) { + wrap << "&"; + type->is_pointer++; + } + wrap << " " << cname << "(" << classtype << classname << " *self"; + + // Walk down the parameter list and Spit out arguments + + p = l->get_first(); + while (p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + wrap << ","; + if ((p->call_type & CALL_REFERENCE) || (p->t->is_reference)) { + p->t->is_pointer--; + } + wrap << p->t->print_full(); + if ((p->call_type & CALL_REFERENCE) || (p->t->is_reference)) { + p->t->is_pointer++; + if (p->t->is_reference) + wrap << "&"; + } + wrap << " " << p->name; + } + p = l->get_next(); + } + + wrap << ") " << ccode; + fprintf(f_wrappers,"%s\n",wrap.get()); + } + } + + // Now add a parameter to the beginning of the function and call + // a language specific function to add it. + + newparms = new ParmList(l); + p = new Parm(0,0); + p->t = new DataType; + p->t->type = T_USER; + p->t->is_pointer = 1; + p->t->id = cpp_id; + p->call_type = 0; + + sprintf(p->t->name,"%s%s", classtype,classname); + p->name = "self"; + newparms->insert(p,0); // Attach parameter to beginning of list + + // Now wrap the thing. The name of the function is iname + + lang->create_function(cname, iname, type, newparms); + delete newparms; + } else { + // Already wrapped this function. Just patch it up + lang->create_command(prev_wrap, iname); + } +} + + +// ----------------------------------------------------------------------------- +// void cplus_emit_static_func(char *classname, char *classtype, char *classrename, +// char *mname, char *mrename, DataType *type, +// ParmList *l, int mode) +// +// This is a generic function to produce a wrapper for a C++ static member function +// or an Objective-C class method. +// +// Specific languages can choose to provide a different mechanism, but this +// function is used to provide a low-level C++ interface. +// +// The mode variable determines whether to create a new function or only to +// add it to the interpreter. This is used to support the %addmethods directive +// +// mode = 0 : Create a wrapper and add it (the normal mode) +// mode = 1 : Assume wrapper was already made and add it to the +// interpreter (%addmethods mode) +// +// Wrapper functions are usually created as follows : +// +// class Foo { +// static int bar(args) +// } +// +// becomes a command called Foo_bar() +// +// if %addmethods mode is set AND there is supporting C code detected, make +// a function from it. +// +// Then we wrap Foo_bar(). The name "Foo_bar" is actually contained in the parameter +// cname. This is so language modules can provide their own names (possibly for +// function overloading). +// +// This function makes no internal checks of the SWIG symbol table. This is +// up to the caller. +// +// Inputs : +// classname = Name of C++ class +// classtype = Type of class (struct, union, class) +// classrename = Renamed version of class (optional) +// mname = Member name +// mrename = Renamed member (optional) +// type = Return type of the function +// l = Parameter list +// mode = addmethods mode +// +// Output : None +// +// ----------------------------------------------------------------------------- + +void cplus_emit_static_func(char *classname, char *, char *classrename, + char *mname, char *mrename, DataType *type, ParmList *l, + int mode) { + Parm *p; + String wrap; + String cname, iname, key; + int i; + char *prefix; + char *prev_wrap = 0; + char *temp_mname; + + cname = ""; + iname = ""; + key = ""; + + // Generate a function name for the member function + + if (!mrename) temp_mname = mname; + else temp_mname = mrename; + char *bc = cplus_base_class(temp_mname); + if (!bc) bc = classname; + if (strlen(bc) == 0) bc = classname; + + // Generate the name of the C wrapper function + if ((!mode) && (!ObjCClass)) { + cname << bc << "::" << mname; + } else { + cname << name_member(mname,bc); + } + + // Generate the scripting name of this function + if (classrename) + prefix = classrename; + else + prefix = classname; + + if (mrename) + iname << name_member(mrename,prefix); + else + iname << name_member(mname,prefix); + + // Perform a hash table lookup to see if we've wrapped anything like this before + + key << cname << "+"; + l->print_types(key); + char *temp = copy_string(iname); + if ((member_hash.add(key,temp)) == -1) { + delete [] temp; + prev_wrap = (char *) member_hash.lookup(key); + } + + if (!prev_wrap) { + if (!((mode) || (ObjCClass))) { + // Not an added method and not objective C, just wrap it + lang->create_function(cname,iname, type, l); + } else { + // This is either an added method or an objective C class function + // + // If there is attached code, use it. + // Otherwise, assume the function has been written already and + // wrap it. + + wrap << "static " << type->print_full() << " " << cname << "("; + + // Walk down the parameter list and Spit out arguments + p = l->get_first(); + while (p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + if (p->t->is_reference) { + p->t->is_pointer--; + } + wrap << p->t->print_full(); + if (p->t->is_reference) { + p->t->is_pointer++; + wrap << "&"; + } + wrap << " " << p->name; + } + p = l->get_next(); + if (p) wrap << ","; + } + wrap << ") "; + if ((mode) && (ccode)) { + wrap << ccode; + } else if (ObjCClass) { + // This is an objective-C method + + wrap << "{\n" << tab4; + + // Emit the function call. + + if ((type->type != T_VOID) || (type->is_pointer)) { + // Declare the return value + + if (type->is_reference) { + type->is_pointer--; + wrap << tab4 << type->print_full() << "& _result = "; + type->is_pointer++; + } else { + wrap << tab4 << type->print_type() << " _result = " << type->print_cast(); + } + } else { + wrap << tab4; + } + wrap << "[ " << classname << " " << mname; // Objective C invocation + i = 0; + p = l->get_first(); + while(p != 0) { + wrap << " " << p->objc_separator; + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + if (p->t->is_reference) { + wrap << "*"; + } + wrap << p->name; + i++; + } + p = l->get_next(); + } + wrap << "];\n"; + + if ((type->type != T_VOID) || (type->is_pointer)) { + if (type->is_reference) { + wrap << tab4 << "return " << type->print_cast() << " &_result;\n"; + } else { + wrap << tab4 << "return _result;\n"; + } + } + wrap << "}\n"; + } + if (ObjCClass || (mode && ccode)) + fprintf(f_wrappers,"%s\n",wrap.get()); + lang->create_function(cname,iname,type,l); + } + } else { + // Already wrapped this function. Just hook up to it. + lang->create_command(prev_wrap, iname); + } +} + +// ----------------------------------------------------------------------------- +// void cplus_emit_destructor(char *classname, char *classtype, char *classrename, +// char *mname, char *mrename, int mode) +// +// Emit a C wrapper around a C++ destructor. +// +// Usually this function is used to do the following : +// class Foo { +// ... +// ~Foo(); +// } +// +// becomes .... +// void delete_Foo(Foo *f) { +// delete f; +// } +// +// Then we wrap delete_Foo(). +// +// Inputs : +// classname = Name of the C++ class +// classtype = Type of class (struct,class,union) +// classrename = Renamed class (optional) +// mname = Name of the destructor +// mrename = Name of the function in the interpreter +// mode = addmethods mode (0 or 1) +// +// Output : None +// +// Side Effects : +// Creates a destructor function and wraps it. +// ----------------------------------------------------------------------------- + +void cplus_emit_destructor(char *classname, char *classtype, char *classrename, + char *mname, char *mrename, int mode) +{ + Parm *p; + DataType *type; + ParmList *l; + String wrap; + String cname,iname; + char *prefix; + + // Construct names for the function + + if (classrename) + prefix = classrename; + else + prefix = classname; + + cname << name_destroy(classname); + if (mrename) + iname << name_destroy(mrename); + else + iname << name_destroy(prefix); + + if (!mode) { + // Spit out a helper function for this member function + wrap << "#define " << cname << "(_swigobj) ("; + if (ObjCClass) { + wrap << "[_swigobj " << mname << "])\n"; // Name of the member is the destructor + } else if (CPlusPlus) + wrap << "delete _swigobj)\n"; + else + wrap << "free ((char *) _swigobj))\n"; + fprintf(f_wrappers,"%s", wrap.get()); + } else { + if (ccode) { + wrap << "static void " << cname << "(" << classtype << classname << " *self) " << ccode; + fprintf(f_wrappers,"%s\n",wrap.get()); + } + } + + // Make a parameter list for this function + + l = new ParmList; + p = new Parm(0,0); + p->t = new DataType; + p->t->type = T_USER; + p->t->is_pointer = 1; + p->t->id = cpp_id; + p->call_type = 0; + sprintf(p->t->name,"%s%s", classtype, classname); + p->name = "self"; + l->insert(p,0); + + type = new DataType; + type->type = T_VOID; + sprintf(type->name,"void"); + type->is_pointer = 0; + type->id = cpp_id; + + // iname is the desired name of the function in the target language + + lang->create_function(cname,iname,type,l); + + delete type; + delete l; + +} + +// ----------------------------------------------------------------------------- +// void cplus_emit_constructor(char *classname, char *classtype, char *classrename, +// char *mname, char *mrename, ParmList *l, int mode) +// +// Creates a C wrapper around a C++ constructor +// +// Inputs : +// classname = name of class +// classtype = type of class (struct,class,union) +// classrename = Renamed class (optional) +// mname = Name of constructor +// mrename = Renamed constructor (optional) +// l = Parameter list +// mode = addmethods mode +// +// Output : None +// +// Side Effects : +// Creates a C wrapper and calls the language module to wrap it. +// ----------------------------------------------------------------------------- + +void cplus_emit_constructor(char *classname, char *classtype, char *classrename, + char *mname, char *mrename, ParmList *l, int mode) +{ + Parm *p; + int i; + DataType *type; + String wrap; + String fcall,cname,iname,argname; + char *prefix; + + // Construct names for the function + + if (classrename) + prefix = classrename; + else + prefix = classname; + + cname << name_construct(classname); + if (mrename) + iname << name_construct(mrename); + else + iname << name_construct(prefix); + + // Create a return type + + type = new DataType; + type->type = T_USER; + sprintf(type->name,"%s%s", classtype,classname); + type->is_pointer = 1; + type->id = cpp_id; + + if (!mode) { + wrap << "#define " << iname << "("; + cname = ""; + cname << iname; + if (ObjCClass) { + fcall << type->print_cast() << "[" << classname << " " << mname; + } else if (CPlusPlus) { + fcall << "new " << classname << "("; + } else { + fcall << type->print_cast() << " calloc(1,sizeof(" + << classtype << classname << "))"; + } + + // Walk down the parameter list and spit out arguments + + i = 0; + p = l->get_first(); + while (p != 0) { + if (ObjCClass) fcall << " " << p->objc_separator; + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + wrap << "_swigarg" << i; + + // Emit an argument in the function call if in C++ mode + + if ((CPlusPlus) || (ObjCClass)) { + fcall << "_swigarg" << i; + } + } + i++; + p = l->get_next(); + if (p) { + wrap << ","; + if ((CPlusPlus) && (!ObjCClass)) + fcall << ","; + } + } + + wrap << ") "; + if (ObjCClass) fcall << "]"; + else if (CPlusPlus) fcall << ")"; + + wrap << "(" << fcall << ")\n"; + fprintf(f_wrappers,"%s",wrap.get()); + } else { + if (ccode) { + wrap << "static " << classtype << classname << " *" << cname << "("; + + // Walk down the parameter list and spit out arguments + + p = l->get_first(); + while (p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + if (p->call_type & CALL_REFERENCE) { + p->t->is_pointer--; + } + wrap << p->t->print_real(p->name); + if (p->call_type & CALL_REFERENCE) { + p->t->is_pointer++; + } + p = l->get_next(); + if (p) { + wrap << ","; + } + } else { + p = l->get_next(); + } + } + wrap << ") " << ccode << "\n"; + fprintf(f_wrappers,"%s\n",wrap.get()); + } + } + + // If we had any C++ references, get rid of them now + + if (!mode) { + p = l->get_first(); + while (p) { + // p->t->is_reference = 0; + p = l->get_next(); + } + } + + // We've now created a C wrapper. We're going to add it to the interpreter + + lang->create_function(cname, iname, type, l); + delete type; +} + +// ----------------------------------------------------------------------------- +// void cplus_emit_variable_get(char *classname, char *classtype, char *classrename, +// char *mname, char *mrename, DataType *type, int mode) +// +// Writes a C wrapper to extract a data member +// +// Usually this function works as follows : +// +// class Foo { +// double x; +// } +// +// becomes : +// +// double Foo_x_get(Foo *obj) { +// return obj->x; +// } +// +// Optimization : 12/31/97 +// +// Now emits a macro like this : +// +// #define Foo_x_get(obj) (obj->x) +// +// Inputs : +// classname = name of C++ class +// classtype = type of class (struct, class, union) +// classrename = Renamed class +// mname = Member name +// mrename = Renamed member +// type = Datatype of the member +// mode = Addmethods mode +// +// Output : None +// +// Side Effects : +// Creates a C accessor function and calls the language module +// to make a wrapper around it. +// ----------------------------------------------------------------------------- + +void cplus_emit_variable_get(char *classname, char *classtype, char *classrename, + char *mname, char *mrename, DataType *type, int mode) { + + Parm *p; + ParmList *l; + String wrap; + String cname, iname, key; + char *prefix; + char *tm; + String source; + char *temp_mname; + char *prev_wrap = 0; + + cname = ""; + iname = ""; + key = ""; + + // First generate a proper name for the get function + + // Get the base class of this member + if (!mrename) temp_mname = mname; + else temp_mname = mrename; + + char *bc = cplus_base_class(temp_mname); + if (!bc) bc = classname; + if (strlen(bc) == 0) bc = classname; + + // Generate the name of the C wrapper function (is always the same, regardless + // of renaming). + + cname << name_get(name_member(mname,bc)); + + // Generate the scripting name of this function + if (classrename) + prefix = classrename; + else + prefix = classname; + + if (mrename) + iname << name_get(name_member(mrename,prefix)); + else + iname << name_get(name_member(mname,prefix)); + + // Now check to see if we have already wrapped a variable like this. + + key << cname; + char *temp = copy_string(iname); + if ((member_hash.add(key,temp)) == -1) { + delete [] temp; + prev_wrap = (char *) member_hash.lookup(key); + } + + // Only generate code if already existing wrapper doesn't exist + if (!prev_wrap) { + if (!mode) { + // Get any sort of typemap that might exist + + source << "obj->" << mname; + + // Now write a function to get the value of the variable + + tm = typemap_lookup("memberout",typemap_lang,type,mname,source,"result"); + + if ((type->type == T_USER) && (!type->is_pointer)) { + type->is_pointer++; + if (tm) { + wrap << "static " << type->print_type() << " " << cname << "(" + << classtype << classname << " *obj) {\n" + << tab4 << type->print_type() << " result;\n" + << tm << "\n" + << tab4 << "return result;\n" + << "}\n"; + } else { + wrap << "#define " << cname << "(_swigobj) " + << "(&_swigobj->" << mname << ")\n"; + } + type->is_pointer--; + } else { + if (tm) { + wrap << "static " << type->print_type() << " " << cname << "(" + << classtype << classname << " *obj) {\n" + << tab4 << type->print_type() << " result;\n" + << tm << "\n" + << tab4 << "return result;\n" + << "}\n"; + } else { + wrap << "#define " << cname << "(_swigobj) ("; + if (!type->is_reference) wrap << type->print_cast(); + else + wrap << "&"; + wrap << " _swigobj->" << mname << ")\n"; + } + } + fprintf(f_wrappers,"%s",wrap.get()); + } + + // Wrap this function + + l = new ParmList; + p = new Parm(0,0); + p->t = new DataType; + p->t->type = T_USER; + p->t->is_pointer = 1; + p->t->id = cpp_id; + p->call_type = 0; + p->name = "self"; + sprintf(p->t->name,"%s%s", classtype,classname); + l->insert(p,0); + + if ((type->type == T_USER) && (!type->is_pointer)) { + type->is_pointer++; + lang->create_function(cname,iname, type, l); + type->is_pointer--; + } else { + int is_ref = type->is_reference; + type->is_reference = 0; + lang->create_function(cname,iname, type, l); + type->is_reference = is_ref; + } + delete l; + } else { + // Already wrapped this function. Just patch it up + lang->create_command(prev_wrap,iname); + } + +} + +// ----------------------------------------------------------------------------- +// void cplus_emit_variable_set(char *classname, char *classtype, char *mname, +// char *cname, char *iname, DataType *type, int mode) +// +// Writes a C wrapper to set a data member +// +// Usually this function works as follows : +// +// class Foo { +// double x; +// } +// +// becomes : +// +// double Foo_x_set(Foo *obj, double value) { +// return (obj->x = value); +// } +// +// Need to handle special cases for char * and for user defined types. +// +// 1. char * +// +// Will free previous contents (if any) and allocate +// new storage. Could be risky, but it's a reasonably +// natural thing to do. +// +// 2. User_Defined +// Will assign value from a pointer. +// Will return a pointer to current value. +// +// +// Optimization, now defined as a C preprocessor macro +// +// Inputs : +// classname = name of C++ class +// classtype = type of class (struct, class, union) +// mname = Member name +// cname = Name of the C function for this (ie. Foo_bar_get) +// iname = Interpreter name of ths function +// type = Datatype of the member +// mode = Addmethods mode +// +// Output : None +// +// Side Effects : +// Creates a C accessor function and calls the language module +// to wrap it. +// ----------------------------------------------------------------------------- + +void cplus_emit_variable_set(char *classname, char *classtype, char *classrename, + char *mname, char *mrename, DataType *type, int mode) { + + Parm *p; + ParmList *l; + String wrap; + int is_user = 0; + char *tm; + String target; + String cname, iname, key; + char *temp_mname; + char *prefix; + char *prev_wrap = 0; + + cname = ""; + iname = ""; + key = ""; + + // First generate a proper name for the get function + + // Get the base class of this member + if (!mrename) temp_mname = mname; + else temp_mname = mrename; + + char *bc = cplus_base_class(temp_mname); + if (!bc) bc = classname; + if (strlen(bc) == 0) bc = classname; + + // Generate the name of the C wrapper function (is always the same, regardless + // of renaming). + + cname << name_set(name_member(mname,bc)); + + // Generate the scripting name of this function + if (classrename) + prefix = classrename; + else + prefix = classname; + + if (mrename) + iname << name_set(name_member(mrename,prefix)); + else + iname << name_set(name_member(mname,prefix)); + + // Now check to see if we have already wrapped a variable like this. + + key << cname; + char *temp = copy_string(iname); + if ((member_hash.add(key,temp)) == -1) { + delete [] temp; + prev_wrap = (char *) member_hash.lookup(key); + } + + // Only generate code if already existing wrapper doesn't exist + + if (!prev_wrap) { + if (!mode) { + + target << "obj->" << mname; + + // Lookup any typemaps that might exist + tm = typemap_lookup("memberin",typemap_lang,type,mname,"val",target); + + // First write a function to set the variable + + if (tm) { + if ((type->type == T_USER) && (!type->is_pointer)) { + type->is_pointer++; + is_user = 1; + } + wrap << "static " << type->print_type() << " " << cname << "(" + << classtype << classname << " *obj, " << type->print_real("val") << ") {\n"; + if (is_user) { + type->is_pointer--; + } + wrap << tm << "\n"; + // Return the member + if (is_user) type->is_pointer++; + wrap << tab4 << "return " << type->print_cast() << " val;\n"; + if (is_user) type->is_pointer--; + wrap << "}\n"; + + } else { + if ((type->type != T_VOID) || (type->is_pointer)){ + if (!type->is_pointer) { + + wrap << "#define " << cname << "(_swigobj,_swigval) ("; + // Have a real value here (ie. not a pointer). + // If it's a user defined type, we'll do something special. + // Otherwise, just assign it. + + if (type->type != T_USER) { + wrap << "_swigobj->" << mname << " = _swigval"; + } else { + wrap << "_swigobj->" << mname << " = *(_swigval)"; + } + wrap << ",_swigval)\n"; + } else { + // Is a pointer type here. If string, we do something + // special. Otherwise. No problem. + if ((type->type == T_CHAR) && (type->is_pointer == 1)) { + String temp; + wrap << "static " << type->print_type() << " " << cname << "(" + << classtype << classname << " *obj, " << type->print_real("val") << ") {\n"; + temp << "obj->" << mname; + if (CPlusPlus) { + wrap << tab4 << "if (" << temp << ") delete [] " << temp << ";\n" + << tab4 << temp << " = new char[strlen(val)+1];\n" + << tab4 << "strcpy((char *)" << temp << ",val);\n"; + } else { + wrap << tab4 << "if (obj->" << mname << ") free(obj->" << mname << ");\n" + << tab4 << "obj->" << mname << " = (char *) malloc(strlen(val)+1);\n" + << tab4 << "strcpy((char *)obj->" << mname << ",val);\n"; + } + wrap << tab4 << "return (char *) val;\n"; + wrap << "}\n"; + } else { + // A normal pointer type of some sort + wrap << "#define " << cname << "(_swigobj,_swigval) ("; + if (type->is_reference) { + wrap << "_swigobj->" << mname << " = *_swigval, _swigval)\n"; + } else { + wrap << "_swigobj->" << mname << " = _swigval,_swigval)\n"; + } + } + } + } + } + } + fprintf(f_wrappers,"%s",wrap.get()); + // Now wrap it. + + l = new ParmList; + p = new Parm(0,0); + p->t = new DataType(type); + p->t->is_reference = 0; + p->call_type = 0; + p->t->id = cpp_id; + if ((type->type == T_USER) && (!type->is_pointer)) p->t->is_pointer++; + if (mrename) + p->name = mrename; + else + p->name = mname; + l->insert(p,0); + p = new Parm(0,0); + p->t = new DataType; + p->t->type = T_USER; + p->call_type = 0; + p->t->is_pointer = 1; + p->t->id = cpp_id; + sprintf(p->t->name,"%s%s", classtype,classname); + p->name = "self"; + l->insert(p,0); + + if ((type->type == T_USER) && (!type->is_pointer)) { + type->is_pointer++; + lang->create_function(cname,iname, type, l); + type->is_pointer--; + } else { + int is_ref = type->is_reference; + type->is_reference = 0; + lang->create_function(cname,iname, type, l); + type->is_reference = is_ref; + } + delete l; + } else { + lang->create_command(prev_wrap,iname); + } +} + +// ----------------------------------------------------------------------------- +// void cplus_support_doc(String &f) +// +// This function adds a supporting documentation entry to the +// end of a class. This should only be used if there is an +// alternative interface available or if additional information is needed. +// +// doc_entry should be set to the class entry before calling this. Otherwise, +// who knows where this text is going to end up! +// +// Inputs : f = String with additional text +// +// Output : None +// +// Side Effects : +// Adds a text block to the current documentation entry. +// +// ----------------------------------------------------------------------------- + +void cplus_support_doc(String &f) { + + DocEntry *de; + if (doc_entry) { + de = new DocText(f.get(),doc_entry); + de->format = 0; + } +} + +// ----------------------------------------------------------------------------- +// void cplus_register_type(char *typename) +// +// Registers a datatype name to be associated with the current class. This +// typename is placed into a local hash table for later use. For example : +// +// class foo { +// public: +// enum ENUM { ... }; +// typedef double Real; +// void bar(ENUM a, Real b); +// } +// +// Then we need to access bar using fully qualified type names such as +// +// void wrap_bar(foo::ENUM a, foo::Real b) { +// bar(a,b); +// } +// +// Inputs : name of the datatype. +// +// Output : None +// +// Side Effects : Adds datatype to localtypes. +// ----------------------------------------------------------------------------- + +void cplus_register_type(char *tname) { + if (current_class) + add_local_type(tname, current_class->classname); +}; + +// ----------------------------------------------------------------------------- +// void cplus_register_scope(Hash *h) +// +// Saves the scope associated with a particular class. It will be needed +// later if anything inherits from us. +// +// Inputs : Hash table h containing the scope +// +// Output : None +// +// Side Effects : Saves h with current class +// ----------------------------------------------------------------------------- + +void cplus_register_scope(Hash *h) { + if (current_class) { + current_class->scope = h; + } +} + +// ----------------------------------------------------------------------------- +// void cplus_inherit_scope(int count, char **baseclass) +// +// Given a list of base classes, this function extracts their former scopes +// and merges them with the current scope. This is needed to properly handle +// inheritance. +// +// Inputs : baseclass = NULL terminated array of base-class names +// +// Output : None +// +// Side Effects : Updates current scope with new symbols. +// +// Copies any special symbols if needed. +// ----------------------------------------------------------------------------- + +void cplus_inherit_scope(int count, char **baseclass) { + CPP_class *bc; + int i; + char *key, *val; + String str; + + if (count && current_class) { + for (i = 0; i < count; i++) { + bc = CPP_class::search(baseclass[i]); + if (bc) { + if (bc->scope) + DataType::merge_scope(bc->scope); + + if (bc->local) { + // Copy local symbol table + key = bc->local->firstkey(); + while (key) { + val = (char *) bc->local->lookup(key); + str = val; + // str.replace(bc->classname,current_class->classname); + localtypes->add(key,copy_string(str)); + key = bc->local->nextkey(); + } + } + } + } + } +} + diff --git a/SWIG/Source/SWIG1.1/emit.cxx b/SWIG/Source/SWIG1.1/emit.cxx new file mode 100644 index 000000000..15bb19450 --- /dev/null +++ b/SWIG/Source/SWIG1.1/emit.cxx @@ -0,0 +1,831 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" +/******************************************************************************* + * $Header$ + * + * File : emit.cxx + * + * This file contains some useful functions for emitting code that would be + * common to all of the interface languages. Mainly this function deals with + * declaring functions external, creating lists of arguments, and making + * function calls. + *******************************************************************************/ + +// ----------------------------------------------------------------------------- +// void emit_banner(FILE *f) +// +// Emits the SWIG identifying banner in the wrapper file +// +// Inputs : f = FILE handle +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void emit_banner(FILE *f) { + + extern char *get_time(); + extern char fn_runtime[]; + + fprintf(f, +"/*\n\ + * FILE : %s\n\ + * \n\ + * This file was automatically generated by SWIG (http://www.swig.org).\n\ + * Version %d.%d %s\n\ + * \n\ + * Portions Copyright (c) 1995-1999\n\ + * The University of Utah, The Regents of the University of California, and\n\ + * The University of Chicago. Permission is granted to use and distribute this\n\ + * file in any manner provided this notice remains intact.\n\ + * \n\ + * This file is not intended to be easily readable and contains a number of \n\ + * coding conventions designed to improve portability and efficiency. Do not make\n\ + * changes to this file unless you know what you are doing--modify the SWIG \n\ + * interface file instead. \n\ + *\n\ + */\n\n", fn_runtime, SWIG_MAJOR_VERSION, SWIG_MINOR_VERSION, SWIG_SPIN); + + fprintf(f,"\n#define SWIGCODE\n"); + +} + +// ----------------------------------------------------------------------------- +// emit_extern_var(char *decl, DataType *t, int extern_type, FILE *f) +// +// Emits an external variables declaration. Extern_type defines the +// type of external declaration. Currently, only C/C++ declarations +// are allowed, but this might be extended to allow Fortran linkage +// someday +// +// Inputs : +// decl = Name of the declaration +// t = Datatype +// extern_type = Numeric code indicating type of extern +// 0 - No "extern" +// 1,2 - Normal extern (C/C++) +// f = FILE handle +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void emit_extern_var(char *decl, DataType *t, int extern_type, FILE *f) { + char *arr = 0; + + if (t->arraystr) arr = t->arraystr; + else arr = ""; + + switch(extern_type) { + + case 0: + // No extern. Just a forward reference + if (t->arraystr) + t->is_pointer--; + + if (t->is_reference) { + t->is_pointer--; + fprintf(f,"%s& %s%s; \n", t->print_full(), decl, arr); + t->is_pointer++; + } else { + fprintf(f,"%s %s%s; \n", t->print_full(), decl,arr); + } + if (t->arraystr) + t->is_pointer++; + break; + case 1: case 2: + if (t->arraystr) + t->is_pointer--; + + // Normal C/C++ extern +// fprintf(f,"#line %d \"%s\"\n", line_number, input_file); + if (t->is_reference) { + t->is_pointer--; + fprintf(f,"extern %s& %s%s; \n", t->print_full(), decl,arr); + t->is_pointer++; + } else { + fprintf(f,"extern %s %s%s; \n", t->print_full(), decl,arr); + } + if (t->arraystr) + t->is_pointer++; + + default: + break; + } +} + +// ----------------------------------------------------------------------------- +// emit_extern_func(char *decl, DataType *t, ParmList *L, int extern_type, +// FILE *f) +// +// Emits an external function declaration (similiar to emit_extern_var). +// +// Inputs : +// decl = Name of declaration +// t = Return datatype +// L = parameter list +// extern_type = Type of extern +// 0 - No "extern" +// 1 - extern +// 2 - extern "C" +// 3 - Function declaration (with arg names) +// f = FILE Handle +// +// Output : None +// +// Side Effects : None +// +// ----------------------------------------------------------------------------- + +void emit_extern_func(char *decl, DataType *t, ParmList *L, int extern_type, FILE *f) { + + switch(extern_type) { + case 0: + if (t->is_reference) { + t->is_pointer--; + fprintf(f,"%s&", t->print_full()); + t->is_pointer++; + } else { + fprintf(f,"%s", t->print_full()); + } + + fprintf(f,"%s(", decl); + L->print_types(f); + fprintf(f,");\n"); + break; + case 1: + // Normal C/C++ extern +// fprintf(f,"#line %d \"%s\"\n", line_number, input_file); + if (t->is_reference) { + t->is_pointer--; + fprintf(f,"extern %s&", t->print_full()); + t->is_pointer++; + } else { + fprintf(f,"extern %s", t->print_full()); + } + fprintf(f,"%s(", decl); + L->print_types(f); + fprintf(f,");\n"); + break; + case 2: + // A C++ --- > C Extern +// fprintf(f,"#line %d \"%s\"\n", line_number, input_file); + if (t->is_reference) { + t->is_pointer--; + fprintf(f,"extern \"C\" %s&", t->print_full()); + t->is_pointer++; + } else { + fprintf(f,"extern \"C\" %s", t->print_full()); + } + fprintf(f,"%s(", decl); + L->print_types(f); + fprintf(f,");\n"); + break; + case 3: + // A function declaration (for inlining ) + if (t->is_reference) { + t->is_pointer--; + fprintf(f,"%s&", t->print_full()); + t->is_pointer++; + } else { + fprintf(f,"%s", t->print_full()); + } + + fprintf(f,"%s(", decl); + L->print_args(f); + fprintf(f,")\n"); + break; + default: + break; + } +} + +// ----------------------------------------------------------------------------- +// char *emit_local(int i) +// +// Returns the name of local variable for parameter i +// +// Inputs : i = Parameter number +// +// Output : NULL terminated ASCII string +// +// Side Effects : Result is left in a static local variable. +// ----------------------------------------------------------------------------- + +char *emit_local(int i) { + static char arg[64]; + + sprintf(arg,"_arg%d", i); + return arg; +} + +// ----------------------------------------------------------------------------- +// int emit_args(char *d, DataType *rt, ParmList *l, FILE *f) +// +// Creates a list of variable declarations for both the return value +// and function parameters. +// +// The return value is always called _result and arguments label as +// _arg0, _arg1, _arg2, etc... +// +// Returns the number of parameters associated with a function. +// +// Inputs : +// d = Name of function +// rt = Return type +// l = Parameter list +// f = FILE Handle +// +// Output : Number of function arguments +// +// Side Effects : None +// +// Note : This function is obsolete. Use emit_args below... +// ----------------------------------------------------------------------------- + +int emit_args(DataType *rt, ParmList *l, FILE *f) { + + Parm *p; + int i; + char temp[64]; + String def; + char *tm; + + // Declare the return variable + + if ((rt->type != T_VOID) || (rt->is_pointer)) { + if ((rt->type == T_USER) && (!rt->is_pointer)) { + + // Special case for return by "value" + + rt->is_pointer++; + fprintf(f,"\t %s _result;\n", rt->print_type()); + rt->is_pointer--; + } else { + + // Normal return value + + fprintf(f,"\t %s _result;\n", rt->print_type()); + } + } + + // Emit function arguments + + i = 0; + p = l->get_first(); + while (p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + sprintf(temp,"_arg%d", i); + if (p->defvalue) { + if ((p->t->is_reference) || ((p->t->type == T_USER) && (p->call_type == CALL_REFERENCE))) + fprintf(f,"\t %s _arg%d = &%s;\n", p->t->print_type(),i, p->defvalue); + else + fprintf(f,"\t %s _arg%d = %s;\n", p->t->print_type(),i, p->defvalue); + } else { + fprintf(f,"\t %s _arg%d;\n", p->t->print_type(),i); + tm = typemap_lookup("arginit", typemap_lang, p->t, p->name,"",temp); + if (tm) { + def << tm; + } + } + + // Check for ignore or default typemaps + + tm = typemap_lookup("default",typemap_lang,p->t,p->name,"",temp); + if (tm) + def << tm; + tm = typemap_lookup("ignore",typemap_lang,p->t,p->name,"",temp); + + if (tm) { + def << tm; + p->ignore = 1; + } + tm = typemap_check("build",typemap_lang,p->t,p->name); + if (tm) { + p->ignore = 1; + } + i++; + } + p = l->get_next(); + } + + fprintf(f,"%s",def.get()); + + // i now contains number of parameters + + return(i); + + } + + +// ----------------------------------------------------------------------------- +// int emit_args(char *d, DataType *rt, ParmList *l, WrapperFunction &f) +// +// Creates a list of variable declarations for both the return value +// and function parameters. +// +// The return value is always called _result and arguments label as +// _arg0, _arg1, _arg2, etc... +// +// Returns the number of parameters associated with a function. +// +// Inputs : +// d = Name of function +// rt = Return type +// l = Parameter list +// f = Wrapper function object +// +// Output : Number of function arguments +// +// Side Effects : None +// +// ----------------------------------------------------------------------------- + +int emit_args(DataType *rt, ParmList *l, WrapperFunction &f) { + + Parm *p; + int i; + char *tm; + + // Declare the return variable + + if ((rt->type != T_VOID) || (rt->is_pointer)) { + if ((rt->type == T_USER) && (!rt->is_pointer)) { + + // Special case for return by "value" + rt->is_pointer++; + f.add_local(rt->print_type(), "_result"); + rt->is_pointer--; + } else { + + // Normal return value + + f.add_local(rt->print_type(), "_result"); + } + } + + // Emit function arguments + + i = 0; + p = l->get_first(); + while (p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)) { + char *temp = emit_local(i); + // Figure out default values + if (((p->t->is_reference) && (p->defvalue)) || + ((p->t->type == T_USER) && (p->call_type == CALL_REFERENCE) && (p->defvalue))) { + String deftmp; + deftmp << "(" << p->t->print_type() << ") &" << p->defvalue; + f.add_local(p->t->print_type(),temp,deftmp.get()); + } else { + String deftmp; + char *dv = 0; + if (p->defvalue) { + deftmp << "(" << p->t->print_type() << ") " << p->defvalue; + dv = deftmp.get(); + } + f.add_local(p->t->print_type(), temp, dv); + tm = typemap_lookup("arginit", typemap_lang, p->t,p->name,"",temp,&f); + if (tm) { + f.code << tm << "\n"; + } + } + // Check for ignore or default typemaps + tm = typemap_lookup("default",typemap_lang,p->t,p->name,"",temp,&f); + if (tm) + f.code << tm << "\n"; + tm = typemap_lookup("ignore",typemap_lang,p->t,p->name,"",temp,&f); + if (tm) { + f.code << tm << "\n"; + p->ignore = 1; + } + tm = typemap_check("build",typemap_lang,p->t,p->name); + if (tm) { + p->ignore = 1; + } + i++; + } + p = l->get_next(); + } + + // i now contains number of parameters + return(i); +} + +// ----------------------------------------------------------------------------- +// int emit_func_call(char *decl, DataType *t, ParmList *l, FILE *f) +// +// Emits code for a function call. +// +// Inputs : +// decl = name of function +// t = Return datatype +// l = Parameter list +// f = FILE Handle +// +// Output : None +// +// Side Effects : None +// +// Note : This function is obsolete +// ----------------------------------------------------------------------------- + +void emit_func_call(char *decl, DataType *t, ParmList *l, FILE *f) { + + int i; + Parm *p; + +// fprintf(f,"#line %d \"%s\"\n", line_number, input_file); + fprintf(f,"\t "); + + // First check if there is a return value + + if ((t->type != T_VOID) || (t->is_pointer)) { + if ((t->type == T_USER) && (!t->is_pointer)) { + + // Special case for return by "value" + // Caution : This *will* cause a memory leak if not + // used properly. + + if (CPlusPlus) { + fprintf(f,"_result = new %s(", t->print_type()); + } else { + t->is_pointer++; + fprintf(f,"_result = %s malloc(sizeof(", t->print_cast()); + t->is_pointer--; + fprintf(f,"%s));\n", t->print_type()); + fprintf(f,"\t*(_result) = "); + } + } else { + // Check if this is a C++ reference + if (t->is_reference) { + t->is_pointer--; + fprintf(f,"%s& _result_ref = ", t->print_full()); + t->is_pointer++; + } else { + + // Normal return values + fprintf(f,"_result = %s", t->print_cast()); + } + } + } + + // Now print out function call + + fprintf(f,"%s(",decl); + + i = 0; + p = l->get_first(); + while(p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)){ + fprintf(f,"%s",p->t->print_arraycast()); + if ((!p->t->is_reference) && (p->call_type & CALL_VALUE)) fprintf(f,"&"); + if ((!(p->call_type & CALL_VALUE)) && + ((p->t->is_reference) || (p->call_type & CALL_REFERENCE))) + fprintf(f,"*"); + fprintf(f,"_arg%d",i); + i++; + } + p = l->get_next(); + if (p != 0) + fprintf(f,","); + } + + fprintf(f,")"); + if ((t->type == T_USER) && (!t->is_pointer)) { + if (CPlusPlus) { + fprintf(f,")"); + } + } + fprintf(f,";\n"); + if (t->is_reference) { + fprintf(f,"\t _result = %s &_result_ref;\n", t->print_cast()); + } +} + + + +// ----------------------------------------------------------------------------- +// int emit_func_call(char *decl, DataType *t, ParmList *l, WrapperFunction &f) +// +// Emits code for a function call (new version). +// +// Exception handling support : +// +// - This function checks to see if any sort of exception mechanism +// has been defined. If so, we emit the function call in an exception +// handling block. +// +// Inputs : +// decl = name of function +// t = Return datatype +// l = Parameter list +// f = WrapperFunction object +// +// Output : None +// +// Side Effects : None +// +// ----------------------------------------------------------------------------- + +void emit_func_call(char *decl, DataType *t, ParmList *l, WrapperFunction &f) { + + int i; + Parm *p; + String fcall; + String exc; + char *tm; + +// f.code << "#line " << line_number << " \"" << input_file << "\"\n"; + fcall << tab4; + + // First check if there is a return value + + if ((t->type != T_VOID) || (t->is_pointer)) { + if ((t->type == T_USER) && (!t->is_pointer)) { + + // Special case for return by "value" + // Caution : This *will* cause a memory leak if not + // used properly. + + if (CPlusPlus) { + fcall << "_result = new " << t->print_type() << "("; + } else { + t->is_pointer++; + fcall << "_result = " << t->print_cast() << " malloc(sizeof("; + t->is_pointer--; + fcall << t->print_type() << "));\n"; + fcall << tab4 << "*(_result) = "; + } + } else { + // Check if this is a C++ reference + if (t->is_reference) { + t->is_pointer--; + fcall << t->print_full() << "& _result_ref = "; + t->is_pointer++; + } else { + + // Normal return value + fcall << "_result = " << t->print_cast(); + } + } + } + + // Now print out function call + + fcall << decl << "("; + + i = 0; + p = l->get_first(); + while(p != 0) { + if ((p->t->type != T_VOID) || (p->t->is_pointer)){ + fcall << p->t->print_arraycast(); + if ((!p->t->is_reference) && (p->call_type & CALL_VALUE)) + fcall << "&"; + if ((!(p->call_type & CALL_VALUE)) && + ((p->t->is_reference) || (p->call_type & CALL_REFERENCE))) + fcall << "*"; + fcall << emit_local(i); + i++; + } + p = l->get_next(); + if (p != 0) + fcall << ","; + } + fcall << ")"; + + if ((t->type == T_USER) && (!t->is_pointer)) { + if (CPlusPlus) { + fcall << ")"; + } + } + fcall << ";\n"; + + if (t->is_reference) { + fcall << tab4 << "_result = "<< t->print_cast() << " &_result_ref;\n"; + } + // Check for exception handling + + if ((tm = typemap_lookup("except",typemap_lang,t,decl,"_result",""))) { + // Found a type-specific mapping + exc << tm; + exc.replace("$function",fcall); + exc.replace("$name",decl); + f.code << exc; + } else if ((tm = fragment_lookup("except",typemap_lang, t->id))) { + exc << tm; + exc.replace("$function",fcall); + exc.replace("$name",decl); + f.code << exc; + } else { + f.code << fcall; + } +} + +// ----------------------------------------------------------------------------- +// void emit_hex(FILE *f) +// +// Emits the default C-code to handle pointers. This is normally contained +// in the SWIG library file 'swigptr.swg' +// +// Inputs : f = FILE handle +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void emit_hex(FILE *f) { + + int stat; + + // Look for a pointer configuration file + + stat = insert_file("swigptr.swg", f); + + if (stat == -1) { + fprintf(stderr,"** Fatal error. Unable to locate 'swigptr.swg'\n"); + SWIG_exit(1); + } +} + +// ----------------------------------------------------------------------------- +// void emit_set_get(char *name, char *iname, DataType *type) +// +// Emits a pair of functions to set/get the value of a variable. +// This should be used as backup in case the target language can't +// provide variable linking. +// +// double foo; +// +// Gets translated into the following : +// +// double foo_set(double x) { +// return foo = x; +// } +// +// double foo_get() { +// return foo; +// } +// +// Need to handle special cases for char * and for user +// defined types. +// +// 1. char * +// +// Will free previous contents (if any) and allocate +// new storage. Could be risky, but it's a reasonably +// natural thing to do. +// +// 2. User_Defined +// Will assign value from a pointer. +// Will return a pointer to current value. +// +// +// Inputs : +// name = Name of variable +// iname = Renamed version of variable +// type = Datatype of the variable +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void emit_set_get(char *name, char *iname, DataType *t) { + + Parm *p; + ParmList *l; + String new_name; + String new_iname; + String wname; + + // First write a function to set the variable of the variable + + if (!(Status & STAT_READONLY)) { + if ((t->type == T_USER) && (!t->is_pointer)) { + t->is_pointer++; + fprintf(f_header,"static %s %s(%s val) {\n", + t->print_type(), name_set(name), t->print_type()); + t->is_pointer--; + } else { + fprintf(f_header,"static %s %s(%s val) {\n", + t->print_type(), name_set(name), t->print_type()); + } + + if ((t->type != T_VOID) || (t->is_pointer)) { + if (!t->is_pointer) { + + // Have a real value here + // If it's a user defined type, we'll do something special. + // Otherwise, just assign it. + + if (t->type != T_USER) { + fprintf(f_header,"\t return (%s) (%s = val);\n", t->print_type(), name); + } else { + fprintf(f_header,"\t %s = *(val);\n", name); + t->is_pointer++; + fprintf(f_header,"\t return (%s) &%s;\n", t->print_type(),name); + t->is_pointer--; + } + } else { + + // Is a pointer type here. If string, we do something + // special. Otherwise. No problem. + + if ((t->type == T_CHAR) && (t->is_pointer == 1)) { + if (CPlusPlus) { + fprintf(f_header,"\t if (%s) delete %s;\n", name,name); + fprintf(f_header,"\t %s = new char[strlen(val)+1];\n",name); + fprintf(f_header,"\t strcpy(%s,val);\n", name); + fprintf(f_header,"\t return %s;\n", name); + } else { + fprintf(f_header,"\t if (%s) free(%s);\n", name,name); + fprintf(f_header,"\t %s = (char *) malloc(strlen(val)+1);\n",name); + fprintf(f_header,"\t strcpy(%s,val);\n", name); + fprintf(f_header,"\t return %s;\n", name); + } + } else { + fprintf(f_header,"\t return (%s) (%s = val);\n", t->print_type(), name); + } + } + } + + fprintf(f_header,"}\n"); + + // Now wrap it. + + l = new ParmList; + p = new Parm(t,0); + if ((t->type == T_USER) && (!t->is_pointer)) p->t->is_pointer++; + p->name = new char[1]; + p->name[0] = 0; + l->append(p); + + new_name = name_set(name); + new_iname = name_set(iname); + + if ((t->type == T_USER) && (!t->is_pointer)) { + t->is_pointer++; + lang->create_function(new_name, new_iname, t, l); + t->is_pointer--; + } else { + lang->create_function(new_name, new_iname, t, l); + } + delete l; + delete p; + if (doc_entry) doc_entry->usage << "\n"; + } + + // Now write a function to get the value of the variable + + if ((t->type == T_USER) && (!t->is_pointer)) { + t->is_pointer++; + fprintf(f_header,"static %s %s() { \n", + t->print_type(), name_get(name)); + fprintf(f_header,"\t return (%s) &%s;\n", t->print_type(), name); + t->is_pointer--; + } else { + fprintf(f_header,"static %s %s() { \n", + t->print_type(), name_get(name)); + fprintf(f_header,"\t return (%s) %s;\n", t->print_type(), name); + } + + fprintf(f_header,"}\n"); + + // Wrap this function + + l = new ParmList; + + new_name = name_get(name); + new_iname = name_get(iname); + + if ((t->type == T_USER) && (!t->is_pointer)) { + t->is_pointer++; + lang->create_function(new_name, new_iname, t, l); + t->is_pointer--; + } else { + lang->create_function(new_name, new_iname, t, l); + } + delete l; +} + + + + diff --git a/SWIG/Source/SWIG1.1/getopt.cxx b/SWIG/Source/SWIG1.1/getopt.cxx new file mode 100644 index 000000000..725eb61aa --- /dev/null +++ b/SWIG/Source/SWIG1.1/getopt.cxx @@ -0,0 +1,141 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" + +/******************************************************************************* + * $Header$ + * + * File : getopt.cxx + * + * This file defines a few functions for handling command line arguments. + * C++ makes this really funky---especially since each language module + * may want to extract it's own command line arguments. + * + * My own special version of getopt. This is a bit weird, because we + * don't know what the options are in advance (they could be determined + * by a language module). + *******************************************************************************/ + +static char **args; +static int numargs; +static int *marked; + +// ----------------------------------------------------------------------------- +// void init_args(int argc, char **argv) +// +// Initializes the argument list. +// +// Inputs : +// argc = Argument count +// argv = Argument array +// +// Output : None +// +// Side Effects : Saves local copy of argc and argv +// ----------------------------------------------------------------------------- + +void +init_args(int argc, char **argv) +{ + int i; + numargs = argc; + args = argv; + marked = new int[numargs]; + for (i = 0; i < argc; i++) { + marked[i] = 0; + } + marked[0] = 1; +} + +// ----------------------------------------------------------------------------- +// void mark_arg(int n) +// +// Marks an argument as being parsed. All modules should do this whenever they +// parse a command line option. +// +// Inputs : n = Argument number +// +// Output : None +// +// Side Effects : Sets a status bit internally +// ----------------------------------------------------------------------------- + +void +mark_arg(int n) { + if (marked) + marked[n] = 1; +} + +// ----------------------------------------------------------------------------- +// void check_options() +// +// Checks for unparsed command line options. If so, issues an error and exits. +// +// Inputs : None +// +// Output : None +// +// Side Effects : exits if there are unparsed options +// ----------------------------------------------------------------------------- + +void check_options() { + + int error = 0; + int i; + + if (!marked) { + fprintf(stderr,"Must specify an input file. Use -help for available options.\n"); + SWIG_exit(1); + } + for (i = 1; i < numargs-1; i++) { + if (!marked[i]) { + fprintf(stderr,"swig error : Unrecognized option %s\n", args[i]); + error=1; + } + } + + if (error) { + fprintf(stderr,"Use 'swig -help' for available options.\n"); + SWIG_exit(1); + } + + if (marked[numargs-1]) { + fprintf(stderr,"Must specify an input file. Use -help for available options.\n"); + SWIG_exit(1); + } +} + +// ----------------------------------------------------------------------------- +// void arg_error() +// +// Generates a generic error message and exits. +// +// Inputs : None +// +// Output : None +// +// Side Effects : Exits +// ----------------------------------------------------------------------------- + +void arg_error() { + fprintf(stderr,"SWIG : Unable to parse command line options.\n"); + fprintf(stderr,"Use 'swig -help' for available options.\n"); + SWIG_exit(1); +} + + + + diff --git a/SWIG/Source/SWIG1.1/hash.cxx b/SWIG/Source/SWIG1.1/hash.cxx new file mode 100644 index 000000000..2bca61568 --- /dev/null +++ b/SWIG/Source/SWIG1.1/hash.cxx @@ -0,0 +1,359 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" + +/******************************************************************************* + * $Header$ + * + * File : hash.cxx + * + * A very simple Hash table class. Could probably make it more elegant with + * templates, but templates are pure evil... + *******************************************************************************/ + +#define INIT_SIZE 119 + +// ----------------------------------------------------------------------------- +// Hash::Hash() +// +// Constructor. Creates a new hash table. +// +// Inputs : None +// +// Output : New Hash object. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +Hash::Hash() { + int i; + hashsize = INIT_SIZE; + hashtable = new Node *[hashsize]; + for (i = 0; i < hashsize; i++) { + hashtable[i] = 0; + } + index = -1; + current = 0; +} + +// ----------------------------------------------------------------------------- +// Hash::~Hash() +// +// Destructor. +// +// Inputs : None +// +// Output : None +// +// Side Effects : Total destruction. +// ----------------------------------------------------------------------------- + +Hash::~Hash() { + int i; + Node *n,*next; + + for (i = 0; i < hashsize; i++) { + if (hashtable[i]) { + n = hashtable[i]; + while (n) { + next = n->next; + delete n; + n = next; + } + } + } + delete [] hashtable; +} + +// ----------------------------------------------------------------------------- +// int Hash::h1(const char *key) +// +// Hashing function. +// +// Inputs : ASCII character string. +// +// Output : Hash table index. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int Hash::h1(const char *key) { + int h = 0; + const char *c; + + c = key; + while (*c) { + h = (128*h + *c) % hashsize; + c++; + } + return h; +} + +// ----------------------------------------------------------------------------- +// int Hash::add(const char *k, void *obj) +// +// Adds a new object to the hash table. +// +// Inputs : +// k = Hash key +// obj = Pointer to an object +// +// Output : 0 on success, -1 if item is already in hash table. +// +// Side Effects : +// Makes a new hash table entry. +// ----------------------------------------------------------------------------- + +int Hash::add(const char *k, void *obj) { + + int hv; + Node *n,*prev; + + hv = h1(k); // Get hash value + n = hashtable[hv]; + prev = n; + while (n) { + if (strcmp(n->key,k) == 0) return -1; // Already in hash table + prev = n; + n = n->next; + } + + // Safe to add this to the table + + n = new Node(k,obj,0); + if (prev) prev->next = n; + else hashtable[hv] = n; + return 0; +} + +// ----------------------------------------------------------------------------- +// int Hash::add(const char *k, void *obj, void (*d)(void *)) +// +// Adds a new object to the hash table. Allows additional specification of +// a callback function for object deletion. +// +// Inputs : +// k = Hash key +// obj = Object pointer +// d = Deletion function +// +// Output : 0 on success, -1 if item is already in hash table. +// +// Side Effects : +// Adds an entry to the hash table +// ----------------------------------------------------------------------------- + +int Hash::add(const char *k, void *obj, void (*d)(void *)) { + + int hv; + Node *n,*prev; + + hv = h1(k); // Get hash value + n = hashtable[hv]; + prev = n; + while (n) { + if (strcmp(n->key,k) == 0) return -1; // Already in hash table + prev = n; + n = n->next; + } + + // Safe to add this to the table + + n = new Node(k,obj,d); + if (prev) prev->next = n; + else hashtable[hv] = n; + return 0; +} + +// ----------------------------------------------------------------------------- +// void *Hash::lookup(const char *k) +// +// Looks up a value in the hash table. Returns a pointer to the object if found. +// +// Inputs : k = key value +// +// Output : Pointer to object or NULL if not found. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void *Hash::lookup(const char *k) { + int hv; + Node *n; + + hv = h1(k); // Get hash value + n = hashtable[hv]; + + while (n) { + if (strcmp(n->key,k) == 0) return n->object; + n = n->next; + } + + return 0; +} + +// ----------------------------------------------------------------------------- +// void Hash::remove(const char *k) +// +// Removes an item from the hash table. Does nothing if item isn't in the +// hash table to begin with. +// +// Inputs : k = Key value +// +// Output : None +// +// Side Effects : Deletes item from hash table. +// ----------------------------------------------------------------------------- + +void Hash::remove(const char *k) { + + int hv; + Node *n,*prev; + + hv = h1(k); // Get hash value + n = hashtable[hv]; + prev = 0; + while (n) { + if (strcmp(n->key,k) == 0) { + // Found it, kill the thing + if (prev) { + prev->next = n->next; + } else { + hashtable[hv] = n->next; + } + delete n; + return; + } + prev = n; + n = n->next; + } +} + +// ----------------------------------------------------------------------------- +// void *Hash::first() +// +// Gets the first item from the hash table or NULL if empty. +// +// Inputs : None +// +// Output : First object in hash table or NULL if hash table is empty. +// +// Side Effects : Resets an internal iterator variable on the hash table. +// ----------------------------------------------------------------------------- + +void *Hash::first() { + index = 0; + current = 0; + + while (!hashtable[index] && (index < hashsize)) + index++; + + if (index >= hashsize) return 0; + current = hashtable[index]; + return current->object; +} + + +// ----------------------------------------------------------------------------- +// char *Hash::firstkey() +// +// Gets the first key from the hash table or NULL if empty. +// +// Inputs : None +// +// Output : First key in hash table or NULL if hash table is empty. +// +// Side Effects : Resets an internal iterator variable on the hash table. +// ----------------------------------------------------------------------------- + +char *Hash::firstkey() { + index = 0; + current = 0; + + while ((index < hashsize) && (!hashtable[index])) + index++; + + if (index >= hashsize) return 0; + current = hashtable[index]; + return current->key; +} + +// ----------------------------------------------------------------------------- +// void *Hash::next() +// +// Returns the next item in the hash table or NULL if there are no more entries. +// A call to first() should generally be made before using this function. +// +// Inputs : None +// +// Output : Pointer to next object or NULL if there are no more objects. +// +// Side Effects : Updates an iterator variable private to the hash table. +// ----------------------------------------------------------------------------- + +void *Hash::next() { + if (index < 0) return first(); + + // Try to move to the next entry + + current = current->next; + + if (current) { + return current->object; + } else { + index++; + while ((index < hashsize) && (!hashtable[index])) + index++; + if (index >= hashsize) return 0; + current = hashtable[index]; + return current->object; + } +} + + +// ----------------------------------------------------------------------------- +// char *Hash::nextkey() +// +// Returns the next key in the hash table or NULL if there are no more entries. +// A call to firstkey() should generally be made before using this function. +// +// Inputs : None +// +// Output : Pointer to next key or NULL if there are no more objects. +// +// Side Effects : Updates an iterator variable private to the hash table. +// ----------------------------------------------------------------------------- + +char *Hash::nextkey() { + if (index < 0) return firstkey(); + + // Try to move to the next entry + + current = current->next; + + if (current) { + return current->key; + } else { + index++; + while (!hashtable[index] && (index < hashsize)) + index++; + if (index >= hashsize) return 0; + current = hashtable[index]; + return current->key; + } +} + + diff --git a/SWIG/Source/SWIG1.1/html.cxx b/SWIG/Source/SWIG1.1/html.cxx new file mode 100644 index 000000000..5930852b9 --- /dev/null +++ b/SWIG/Source/SWIG1.1/html.cxx @@ -0,0 +1,598 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "swig.h" +#include "html.h" + +/******************************************************************************* + * $Header$ + * + * File : html.cxx + * + * HTML specific functions for producing documentation. + *******************************************************************************/ + +#define PRE 0 +#define FORMAT 1 + +// ----------------------------------------------------------------------------- +// HTML::HTML() +// +// Constructor. Creates a new HTML documentation module object. +// +// Inputs : None +// +// Output : HTML Object +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +HTML::HTML() { + sect_count = 0; + last_section = 0; + + // Initialize default tags for various parts of the documentation + + tag_body = ":"; + tag_title = "

:

"; + tag_contents = "

:

"; + tag_section = "

:

"; + tag_subsection = "

:

"; + tag_subsubsection = "

:

"; + tag_usage = "

:"; + tag_descrip = "

:
"; + tag_text = "

"; + tag_cinfo = ""; + tag_preformat = "

:
"; +} + +// ----------------------------------------------------------------------------- +// char *HTML::start_tag(char *tag) +// +// Utility function for returning the first part of an HTML tag variable. +// A tag must look like this : +// +// ":" +// +// The start tag for this would be "" +// +// Inputs : tag = HTML tag string +// +// Output : Staring portion of the tag variable. +// +// Side Effects : None. +// ----------------------------------------------------------------------------- + +char *HTML::start_tag(char *tag) { + static String stag; + char *c; + + stag = ""; + c = tag; + while ((*c) && (*c != ':')) { + stag << *c; + c++; + } + return stag.get(); +} + +// ----------------------------------------------------------------------------- +// char *HTML::end_tag(char *tag) +// +// Utility for returning an end-tag. The counterpart to start_tag(). +// +// Inputs : tag = HTML tag string +// +// Output : Ending portion of tag variable. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +char *HTML::end_tag(char *tag) { + static String etag; + char *c; + + etag = ""; + c = tag; + while ((*c) && (*c != ':')) { + c++; + } + if (*c) { + c++; + while (*c) { + etag << *c; + c++; + } + } + return etag.get(); +} + +// ----------------------------------------------------------------------------- +// void HTML::print_string(char *s, String &str, int mode) +// +// Outputs the contents of string s into String str. If mode is 1, we +// will reformat the text and apply a few common HTML character +// substitutions. +// +// Inputs : s = Documentation text string +// mode = Formatting mode (0 = preformat, 1 = formatted) +// +// Output : str = Output is append to str. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void HTML::print_string(char *s, String &str,int mode) { + char *c; + c = s; + while (*c) { + switch(*c) { + case '\"': + str << """; + break; + case '&': + str << "&"; + break; + case '<': + if (mode == PRE) + str << "<"; + else + str << (char) *c; + break; + case '>': + if (mode == PRE) + str << ">"; + else + str << (char) *c; + break; + default : + str << (char ) *c; + break; + } + c++; + } +} + +// ----------------------------------------------------------------------------- +// void HTML::print_decl(DocEntry *de) +// +// Generates documentation for a declaration. +// +// Inputs : de = Documentation entry +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void HTML::print_decl(DocEntry *de) { + + char *c; + c = de->usage.get(); + while ((*c) && ((*c == ' ') || (*c == '\t') || (*c == '\n'))) c++; + if (c) { + s_doc << start_tag(tag_usage); + print_string(c,s_doc,PRE); + s_doc << end_tag(tag_usage) << "\n"; + } else return; + + // Only print this if there is information + + if ((strlen(de->cinfo.get()) && de->print_info) || strlen(de->text.get())) { + s_doc << start_tag(tag_descrip); + if (!de->format) + s_doc << start_tag(tag_preformat); + } + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << start_tag(tag_cinfo); + s_doc << "[ "; + print_string(c,s_doc,PRE); + s_doc << " ]" << end_tag(tag_cinfo) << "\n"; + if (de->format) s_doc << "
"; + } + } + + c = de->text.get(); + if (strlen(c) > 0) { + print_string(c,s_doc,de->format); + } + + if ((strlen(de->cinfo.get()) && de->print_info) || strlen(de->text.get())) { + if (!de->format) s_doc << end_tag(tag_preformat); + s_doc << end_tag(tag_descrip) << "\n"; + } + + s_doc << "\n"; +} + +// ----------------------------------------------------------------------------- +// void HTML::print_text(DocEntry *de) +// +// Generates documentation for a text-block. Strips any leading whitespace. +// +// Inputs : de = Documentation entry +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void HTML::print_text(DocEntry *de) { + char *c; + c = de->text.get(); + if (strlen(c) > 0) { + s_doc << start_tag(tag_text); + if (!de->format) + s_doc << start_tag(tag_preformat); + print_string(c,s_doc,de->format); + if (!de->format) + s_doc << end_tag(tag_preformat) << "\n"; + s_doc << end_tag(tag_text) << "\n"; + } +} + +// ----------------------------------------------------------------------------- +// void HTML::title(DocEntry *de) +// +// Generates the title for an HTML document. +// +// Inputs : de = Title documentation entry +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void HTML::title(DocEntry *de) { + char *c; + c = de->usage.get(); + if (strlen(c) > 0) { + s_title << "\n" + << "\n"; + print_string(c,s_title,PRE); + s_title << "\n" + << start_tag(tag_body) << "\n"; + + s_title << start_tag(tag_title); + print_string(c,s_title,PRE); + s_title << end_tag(tag_title) << "\n"; + } + + if (!de->format) + s_title << start_tag(tag_preformat); + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_title << start_tag(tag_cinfo) << "[ "; + print_string(c,s_title,de->format); + s_title << " ]" << end_tag(tag_cinfo); + if (de->format) + s_title << "
\n"; + else + s_title << "\n"; + } + } + + c = de->text.get(); + if (strlen(c)) { + print_string(c,s_title,de->format); + } + if (!de->format) + s_title << end_tag(tag_preformat) << "\n"; +} + +// ----------------------------------------------------------------------------- +// void HTML::newsection(DocEntry *de, int sectnum) +// +// Creates a new section. sect_count is used to determine the formatting of +// the header. Also fills in a table of contents +// +// Inputs : +// de = Documentation Entry +// sectnum = Section number +// +// Output : None +// +// Side Effects : +// Creates a new subsection. Updates HTML table of contents. +// ----------------------------------------------------------------------------- + +void HTML::newsection(DocEntry *de,int sectnum) { + int i,f; + char *c; + + char *tag; + + sect_num[sect_count] = sectnum; + sect_count++; + + f = sect_count + 1; + if (f > 5) f = 5; + + // Form table of contents + // if sect_count > last_section. We need to indent + // if sect_count < last_section. We need to pop out + + if (sect_count > last_section) { + for (i = 0; i < sect_count - last_section; i++) + contents << "
    "; + } else if (sect_count < last_section) { + for (i = 0; i < last_section - sect_count; i++) + contents << "
"; + } + + last_section = sect_count; + contents << "
  • "; + + // Figure out the tag fields + + switch(f) { + case 1: + tag = tag_title; + break; + case 2: + tag = tag_section; + break; + case 3: + tag = tag_subsection; + break; + case 4: + tag = tag_subsubsection; + break; + default: + tag = tag_subsubsection; + } + + s_doc << "\">\n" + << start_tag(tag); + + for (i = 0; i < sect_count; i++) { + s_doc << sect_num[i] << "."; + contents << sect_num[i] << "."; + } + c = de->usage.get(); + s_doc << " "; + contents << " "; + print_string(c,s_doc,PRE); + print_string(c,contents,PRE); + s_doc << end_tag(tag) << "\n"; + contents << "\n"; + + if (!de->format) + s_doc << start_tag(tag_preformat); + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << start_tag(tag_cinfo) << "[ "; + print_string(c,s_doc,de->format); + s_doc << " ]" << end_tag(tag_cinfo); + if (de->format) + s_doc << "
    \n"; + else + s_doc << "\n"; + } + } + + // If there is a description text. Print it + + c = de->text.get(); + if (strlen(c) > 0) { + print_string(c,s_doc,de->format); + s_doc << "\n"; + } + if (!de->format) + s_doc << end_tag(tag_preformat) << "\n"; + +} + +// ----------------------------------------------------------------------------- +// void HTML::endsection() +// +// Ends a subsection. It is an error to call this without first calling +// newsection previously. +// +// Inputs : None +// +// Output : None +// +// Side Effects : Closes current section and goes back to parent. +// +// ----------------------------------------------------------------------------- + +void HTML::endsection() { + if (sect_count > 0) sect_count--; +} + +// ----------------------------------------------------------------------------- +// void HTML::separator() +// +// Prints a separator after the declaration of a C++ class. Currently +// does nothing in HTML mode. +// +// Inputs : None +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void HTML::separator() { +} + +// ----------------------------------------------------------------------------- +// void HTML::init(char *filename) +// +// Initializes the HTML module and opens up the documentation file. +// +// Inputs : filename = Name of documentation file (without a suffix) +// +// Output : None +// +// Side Effects : Opens documentation file. +// ----------------------------------------------------------------------------- + +void HTML::init(char *filename) { + char f[256]; + + sprintf(f,"%s.html",filename); + f_doc = fopen(f,"w"); + if (f_doc == NULL) { + fprintf(stderr,"Unable to open %s\n",f); + SWIG_exit(1); + } + /* Print a HTML banner */ + fprintf(f_doc,"\n"); + +} + +// ----------------------------------------------------------------------------- +// void HTML::close(void) +// +// Dumps the table of contents and forms the final documentation file. Closes +// the documentation file upon completion. +// +// Inputs : None +// +// Output : None +// +// Side Effects : Closes documentation file. +// ----------------------------------------------------------------------------- + +void HTML::close(void) { + + int i; + for (i = 0; i < last_section; i++) + contents << "\n"; + + fprintf(f_doc,"%s\n",s_title.get()); + if (last_section) { + fprintf(f_doc,"%s Contents %s\n",start_tag(tag_contents),end_tag(tag_contents)); + fprintf(f_doc,"%s\n",contents.get()); + } + fprintf(f_doc,"%s\n",s_doc.get()); + fprintf(f_doc,"%s\n", end_tag(tag_body)); + fprintf(f_doc,"\n"); + fclose(f_doc); +} + +// ----------------------------------------------------------------------------- +// void HTML::style(char *name, char *value) +// +// Process parameters given with the %style directive. Does nothing if an +// unrecognized parameter is given. +// +// Inputs : +// name = name of style parameter +// value = ASCII string with value of parameter. +// +// Output : None +// +// Side Effects : Updates internal style parameters. +// ----------------------------------------------------------------------------- + +void HTML::style(char *name, char *value) { + if (strcmp(name,"html_title") == 0) { + if (value) + tag_title = copy_string(value); + } else if (strcmp(name,"html_contents") == 0) { + if (value) + tag_contents = copy_string(value); + } else if (strcmp(name,"html_section") == 0) { + if (value) + tag_section = copy_string(value); + } else if (strcmp(name,"html_subsection") == 0) { + if (value) + tag_subsection = copy_string(value); + } else if (strcmp(name,"html_subsubsection") == 0) { + if (value) + tag_subsubsection = copy_string(value); + } else if (strcmp(name,"html_usage") == 0) { + if (value) + tag_usage = copy_string(value); + } else if (strcmp(name,"html_descrip") == 0) { + if (value) + tag_descrip = copy_string(value); + } else if (strcmp(name,"html_text") == 0) { + if (value) + tag_text = copy_string(value); + } else if (strcmp(name,"html_cinfo") == 0) { + if (value) + tag_cinfo = copy_string(value); + } else if (strcmp(name,"html_preformat") == 0) { + if (value) + tag_preformat = copy_string(value); + } else if (strcmp(name,"html_body") == 0) { + if (value) + tag_body = copy_string(value); + } +} + +// ----------------------------------------------------------------------------- +// void HTML::parse_args(int argc, char **argv) +// +// Parse command line options given on the SWIG command line. +// +// Inputs : +// argc = argument count +// argv = argument array +// +// Output : None +// +// Side Effects : Marks arguments as being parsed. +// ----------------------------------------------------------------------------- + +static char *html_usage = "\ +HTML Documentation Options (available with -dhtml)\n\ + None available.\n\n"; + +void HTML::parse_args(int argc, char **argv) { + int i; + + for (i = 0; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-help") == 0) { + fputs(html_usage,stderr); + } + } + } +} + + + + + + + + + + + + diff --git a/SWIG/Source/SWIG1.1/html.h b/SWIG/Source/SWIG1.1/html.h new file mode 100644 index 000000000..2dfc0cab5 --- /dev/null +++ b/SWIG/Source/SWIG1.1/html.h @@ -0,0 +1,76 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * html.h + * + * HTML specific functions for producing documentation. + ***********************************************************************/ + +class HTML : public Documentation { +private: + FILE *f_doc; + void print_string(char *s, String &str, int mode); + char *start_tag(char *); + char *end_tag(char *); + int sect_count; + int sect_num[20]; + int last_section; + String s_doc; + String s_title; + String contents; + char *tag_body; + char *tag_title; + char *tag_contents; + char *tag_section; + char *tag_subsection; + char *tag_subsubsection; + char *tag_usage; + char *tag_descrip; + char *tag_text; + char *tag_cinfo; + char *tag_preformat; +public: + HTML(); + void parse_args(int argc, char **argv); + void title(DocEntry *de); + void newsection(DocEntry *de, int sectnum); + void endsection(); + void print_decl(DocEntry *de); + void print_text(DocEntry *de); + void separator(); + void init(char *filename); + void close(void); + void style(char *name, char *value); +}; + + + + + + + + + + + + + + + + + diff --git a/SWIG/Source/SWIG1.1/include.cxx b/SWIG/Source/SWIG1.1/include.cxx new file mode 100644 index 000000000..f0bbe4828 --- /dev/null +++ b/SWIG/Source/SWIG1.1/include.cxx @@ -0,0 +1,586 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" +#include +#include +#include + +/******************************************************************************* + * $Header$ + * + * File : include.cxx + * + * Code for including files into a wrapper file. + * + *******************************************************************************/ + +/* Delimeter used in accessing files and directories */ + +#ifdef MACSWIG +#define DELIMETER ':' +#else +#define DELIMETER '/' +#endif + +/* Linked list containing search directories */ + +struct Dnode { + char *dirname; + Dnode *next; +}; + +Dnode ihead, iz; +int include_init = 0; + +/* Linked list containing included files */ + +struct Inode { + char *name; + Inode *next; +}; + +Inode *include_list = 0; + +// ----------------------------------------------------------------------------- +// void add_directory(char *dirname) +// +// Adds a directory to the SWIG search path. +// +// Inputs : dirname = Pathname +// +// Output : None +// +// Side Effects : Adds dirname to linked list of pathnames. +// ----------------------------------------------------------------------------- + +void add_directory(char *dirname) { + Dnode *d; + + if (!include_init) { + ihead.next = &iz; + iz.next = &iz; + iz.dirname = new char[2]; + iz.dirname[0] = 0; + include_init = 1; + } + + d = new Dnode; + d->dirname = new char[strlen(dirname)+1]; + strcpy(d->dirname,dirname); + d->next = ihead.next; + ihead.next = d; + +} + +// ----------------------------------------------------------------------------- +// int add_iname(char *name) +// +// Adds an include file to the list of processed files. If already present, +// returns 1. +// +// Inputs : name = filename +// +// Output : 0 on success, 1 on failure. +// +// Side Effects : Adds name to linked list. +// ----------------------------------------------------------------------------- + +int add_iname(char *name) { + + Inode *newi, *i; + + // if (WrapExtern) return 0; // Still thinking about this patch. + if (include_list) { + /* Search list */ + i = include_list; + while (i) { + if (strcmp(i->name, name) == 0) return 1; + i = i->next; + } + } + + newi = new Inode; + newi->name = new char[strlen(name)+1]; + strcpy(newi->name, name); + newi->next = include_list; + include_list = newi; + return 0; +} + +// ----------------------------------------------------------------------------- +// void check_suffix(char *name) +// +// Checks the suffix of an include file to see if we need to handle it +// differently. C and C++ source files need a little extra help. +// +// Inputs : name = include file name. +// +// Output : None +// +// Side Effects : +// Sets ForceExtern status variable if a C/C++ source file +// is detected. +// +// ----------------------------------------------------------------------------- + +void check_suffix(char *name) { + char *c; + + if (!name) return; + if (strlen(name) == 0) return; + c = name+strlen(name)-1; + while (c != name) { + if (*c == '.') break; + c--; + } + if (c == name) return; + + /* Check suffixes */ + + if (strcmp(c,".c") == 0) { + ForceExtern = 1; + } else if (strcmp(c,".C") == 0) { + ForceExtern = 1; + } else if (strcmp(c,".cc") == 0) { + ForceExtern = 1; + } else if (strcmp(c,".cxx") == 0) { + ForceExtern = 1; + } else if (strcmp(c,".c++") == 0) { + ForceExtern = 1; + } else if (strcmp(c,".cpp") == 0) { + ForceExtern = 1; + } else { + ForceExtern = 0; + } +} +// ----------------------------------------------------------------------------- +// int include_file(char *name) +// +// Includes a new SWIG wrapper file. Returns -1 if file not found. +// +// Inputs : name = filename +// +// Output : 0 on success. -1 on failure. +// +// Side Effects : sets scanner to read from new file. +// ----------------------------------------------------------------------------- + +int include_file(char *name) { + + FILE *f; + char filename[256]; + int found = 0; + Dnode *d; + extern void scanner_file(FILE *); + + if (!include_init) return -1; // Not initialized yet + if (add_iname(name)) { + if (Verbose) fprintf(stderr,"file %s already included.\n", name); + return -1; // Already included this file + } + + if (Verbose) { + fprintf(stderr,"Wrapping %s...\n", name); + fprintf(stderr,"Looking for ./%s\n", name); + } + + if ((f = fopen(name,"r")) != NULL) { + input_file = new char[strlen(name)+1]; + strcpy(input_file,name); + scanner_file(f); + check_suffix(name); + return 0; + } + + // Now start searching libraries + + d = ihead.next; // Start of search list + while (d != &iz) { + // Look for the wrap file in language directory + sprintf(filename,"%s%c%s%c%s", d->dirname,DELIMETER,LibDir,DELIMETER,name); + if (Verbose) fprintf(stderr,"Looking for %s\n", filename); + if((f = fopen(filename,"r")) != NULL) { + found = 1; + } else { + sprintf(filename,"%s%c%s", d->dirname, DELIMETER,name); + if (Verbose) fprintf(stderr,"Looking for %s\n", filename); + if ((f = fopen(filename,"r")) != NULL) { + found = 1; + } + } + if (found) { + // Found it, open it up for input + input_file = new char[strlen(filename)+1]; + strcpy(input_file,filename); + scanner_file(f); + check_suffix(name); + return 0; + } + d = d->next; + } + + if (!found) fprintf(stderr,"%s : Line %d. Unable to find include file %s (ignored).\n",input_file, line_number, name); + + return -1; +} + + +static char buffer[1024]; + +// ----------------------------------------------------------------------------- +// void copy_data(FILE *f1, FILE *f2) +// +// Copies data from file f1 to file f2. +// +// Inputs : f1 = FILE 1 +// f2 = FILE 2 +// +// Output : None +// +// Side Effects : Closes file f1 upon exit. +// ----------------------------------------------------------------------------- + +void copy_data(FILE *f1, FILE *f2) { + + while (fgets(buffer,1023,f1)) { + fputs(buffer, f2); + } + fclose(f1); +} + +// ----------------------------------------------------------------------------- +// void copy_data(FILE *f1, String *s2) +// +// Copies data from file f1 to String s2. +// +// Inputs : f1 = FILE 1 +// s2 = String +// +// Output : None +// +// Side Effects : Closes file f1 upon exit. +// ----------------------------------------------------------------------------- + +void copy_data(FILE *f1, String &s2) { + + while (fgets(buffer,1023,f1)) { + s2 << buffer; + } + fclose(f1); +} + +// ----------------------------------------------------------------------------- +// int insert_file(char *name, FILE *f) +// +// Looks for a file and inserts into file f. +// +// Inputs : name = filename +// f = FILE +// +// Output : 0 on success, -1 on failure. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int insert_file(char *name, FILE *f_out) { + + FILE *f; + char filename[256]; + int found = 0; + Dnode *d; + + if (!include_init) return -1; // Not initialized yet + if (add_iname(name)) { + if (Verbose) fprintf(stderr,"file %s already included.\n", name); + return -1; // Already included this file + } + + if (Verbose) fprintf(stderr,"Looking for ./%s\n", name); + if ((f = fopen(name,"r")) != NULL) { + copy_data(f,f_out); + return 0; + } + + // Now start searching libraries + + d = ihead.next; // Start of search list + while (d != &iz) { + // Look for the wrap file in language directory + sprintf(filename,"%s%c%s%c%s", d->dirname,DELIMETER,LibDir,DELIMETER,name); + if (Verbose) fprintf(stderr,"Looking for %s\n", filename); + if((f = fopen(filename,"r")) != NULL) { + found = 1; + } else { + sprintf(filename,"%s%c%s", d->dirname, DELIMETER, name); + if (Verbose) fprintf(stderr,"Looking for %s\n", filename); + if ((f = fopen(filename,"r")) != NULL) { + found = 1; + } + } + if (found) { + copy_data(f,f_out); + return 0; + } + d = d->next; + } + + if ((!found) && (Verbose)) fprintf(stderr,"unable to find %s. (Ignored)\n",name); + return -1; +} + +// ----------------------------------------------------------------------------- +// void swig_append(char *filename, FILE *f) +// +// Appends the contents of filename to stream f. +// +// Inputs : +// filename = File to append +// f = FILE handle +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void swig_append(char *filename, FILE *f) { + + FILE *in_file; + + if ((in_file = fopen(filename,"r")) == NULL) { + fprintf(stderr,"** SWIG ERROR ** file %s not found.\n",filename); + FatalError(); + return; + } + while (fgets(buffer,1023,in_file)) { + fputs(buffer, f); + } + fclose(in_file); +} + + +// ----------------------------------------------------------------------------- +// int get_file(char *name, String &str) +// +// Looks for a file and converts it into a String. +// +// Inputs : name = filename +// str = String +// +// Output : 0 on success, -1 on failure. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int get_file(char *name, String &str) { + + FILE *f; + char filename[256]; + int found = 0; + Dnode *d; + + if (!include_init) return -1; // Not initialized yet + + if (Verbose) fprintf(stderr,"Looking for %s\n", name); + if ((f = fopen(name,"r")) != NULL) { + copy_data(f,str); + return 0; + } + + // Now start searching libraries + + d = ihead.next; // Start of search list + while (d != &iz) { + // Look for the wrap file in language directory + sprintf(filename,"%s%c%s%c%s", d->dirname,DELIMETER,LibDir,DELIMETER,name); + if (Verbose) fprintf(stderr,"Looking for %s\n", filename); + if((f = fopen(filename,"r")) != NULL) { + found = 1; + } else { + sprintf(filename,"%s%c%s", d->dirname, DELIMETER, name); + if (Verbose) fprintf(stderr,"Looking for %s\n", filename); + if ((f = fopen(filename,"r")) != NULL) { + found = 1; + } + } + if (found) { + copy_data(f,str); + return 0; + } + d = d->next; + } + + if ((!found)) fprintf(stderr,"SWIG Error. Unable to find %s. Possible installation problem.\n",name); + FatalError(); + return -1; +} + +static char *libs[1000]; +static int nlibs = 0; + +// ----------------------------------------------------------------------------- +// void library_add(char *name) +// +// Adds a filename to the list of libraries. This is usually only called by +// the SWIG main program. +// +// Inputs : name = library name +// +// Outputs: None +// +// Side Effects : Adds the library name to the libs array above +// ----------------------------------------------------------------------------- + +void library_add(char *name) { + int i; + + // Check to make sure it's not already added + + if (!(*name)) return; + + for (i = 0; i < nlibs; i++) { + if (strcmp(libs[i],name) == 0) return; + } + + libs[nlibs] = copy_string(name); + nlibs++; +} + +// ----------------------------------------------------------------------------- +// void library_insert() +// +// Starts parsing all of the SWIG library files. +// +// Inputs : None +// +// Output : None +// +// Side Effects : Opens and attaches all of the specified library files to +// the scanner. +// +// Bugs : Opens all of the files. Will fail if there are too many open files. +// +// ----------------------------------------------------------------------------- + +void library_insert() { + int i; + + i = nlibs-1; + while (i >= 0) { + include_file(libs[i]); + i--; + } +} + +// ----------------------------------------------------------------------------- +// int checkout(char *filename,char *dest) +// +// Tries to check a file out of the SWIG library. If found, it will save it in +// the current directory. This is a useful mechanism for using SWIG as a code +// manager and for extracting library files. +// +// Inputs : filename = Library file +// dest = Destination file +// +// Output : 0 on success +// -1 on failure. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int checkout_file(char *filename,char *dest) { + + FILE *f1; + char tempn[256]; + + // First check to see if the file already exists in current directory + f1 = fopen(dest,"r"); + if (f1) { + if (Verbose) + fprintf(stderr,"Warning. Unable to check-out %s. File already exists.\n", filename); + fclose(f1); + return -1; + } + + while (!f1) { + sprintf(tempn,"%s%d",dest,rand()); + f1 = fopen(tempn,"r"); + if (f1) { + fclose(f1); + f1 = 0; + } else { + f1 = fopen(tempn,"w"); + if (!f1) { + fprintf(stderr,"Unable to open %s for writing\n", tempn); + return -1; + } + } + } + + // Now try to insert the library file into the destination file + if ((insert_file(filename,f1)) == -1) { + fprintf(stderr,"Unable to check-out '%s'. File does not exist in SWIG library.\n",filename); + fclose(f1); + remove(tempn); // Unsuccessful, remove file we created + return -1; + } + fclose(f1); + // Now move the file + rename(tempn,dest); + return 0; +} + + +// ----------------------------------------------------------------------------- +// int checkin_file(char *dir, char *lang, char *source,char *dest) +// +// Attempts to check a file into the SWIG library. +// +// Inputs : dir = Location of the SWIG library. +// lang = Language specific subdirectory. +// source = Source file. +// dest = Destination file. +// +// Output : 0 on success +// -1 on failure. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int checkin_file(char *dir, char *lang, char *source, char *dest) { + + FILE *f1; + char tempn[256]; + String s; + + // First check to see if the file exists + + f1 = fopen(source,"r"); + if (!f1) return -1; + + copy_data(f1,s); + + // Now try to open the destination file + sprintf(tempn,"%s/%s/%s", dir,lang,dest); + f1 = fopen(tempn,"w"); + if (!f1) return -1; + fprintf(f1,"%s",s.get()); + fclose(f1); + return 0; +} + + + + diff --git a/SWIG/Source/SWIG1.1/internal.h b/SWIG/Source/SWIG1.1/internal.h new file mode 100644 index 000000000..eefd33dcd --- /dev/null +++ b/SWIG/Source/SWIG1.1/internal.h @@ -0,0 +1,216 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * internals.h + * + * Contains global variables used in libswig, but which are otherwise + * inaccessible to the user. + * + ***********************************************************************/ + +#include "swig.h" + +// ------------------------------------------------------------------- +// class DocTitle : public DocEntry +// +// Top level class for managing documentation. Prints out a title, +// date, etc... +// ------------------------------------------------------------------- + +class DocTitle : public DocEntry { +public: + DocTitle(char *title, DocEntry *_parent); // Create a new title + void output(Documentation *d); // Output documentation +}; + +// -------------------------------------------------------------------- +// class DocSection : public DocEntry +// +// Documentation entry for a section +// -------------------------------------------------------------------- + +class DocSection : public DocEntry { +public: + DocSection(char *section, DocEntry *_parent); + void output(Documentation *d); +}; + +// -------------------------------------------------------------------- +// class DocFunction : public DocEntry +// +// Documentation entry for generic sorts of declarations +// -------------------------------------------------------------------- + +class DocDecl : public DocEntry { +public: + DocDecl(char *fname, DocEntry *_parent); + DocDecl(DocEntry *de, DocEntry *_parent); + void output(Documentation *d); +}; + +// -------------------------------------------------------------------- +// class DocClass : public DocEntry +// +// Documentation entry for a C++ class or C struct +// -------------------------------------------------------------------- + +class DocClass : public DocEntry { +public: + DocClass(char *classname, DocEntry *_parent); + void output(Documentation *d); +}; + +// -------------------------------------------------------------------- +// class DocText : public DocEntry +// +// Documentation entry for some plain ole text. Declared using +// the %text %{,%} directive. +// -------------------------------------------------------------------- + +class DocText : public DocEntry { +public: + DocText(char *_text, DocEntry *_parent); + void output(Documentation *d); +}; + +// -------------------------------------------------------------------- +// class CommentHandler +// +// Class for managing comment processing. +// -------------------------------------------------------------------- + +class CommentHandler { +public: + CommentHandler(); + CommentHandler(CommentHandler *c); + ~CommentHandler(); + void add_comment(char *text, int line_num, int col, char *file); // Add a comment + void set_entry(DocEntry *d); // Set documentation entry + static void cleanup(); // Clean-up everything before quitting + void style(char *name, char *value); + void parse_args(int argc, char **argv); // Parse command line options + + // Comment handling style parameters + int skip_lines; // # blank lines before comment is throw away + int location; // Comment location (BEFORE or AFTER) + int chop_top; // Lines to chop from the top of a comment + int chop_bottom; // Lines to chop from the bottom + int chop_left; // Characters to chop from left + int chop_right; // Characters to chop from right + int untabify; // Expand tabs + int ignore; // Ignore comments +}; + +#define BEFORE 0 +#define AFTER 1 + + +extern int include_file(char *); // Insert library file +extern char category[256]; +extern char title[256]; +extern DocEntry *doc_entry; +extern DocEntry *doctitle; // The very first docentry +extern DocEntry *doc_stack[256]; // Stack of documentation entries +extern CommentHandler *handler_stack[256]; // Stack of comment handlers +extern int doc_stack_top; // Top of stack + +extern Language *lang; +extern Documentation *doc; +extern CommentHandler *comment_handler; // Comment handling system +extern void swig_append(char *, FILE *); +extern int Stat_func, Stat_var, Stat_const; +extern int IgnoreDoc; +extern int ForceExtern; +extern int WrapExtern; +extern String CCode; +extern int GenerateDefault; +extern int type_id; +extern char *ConfigFile; +extern char *objc_construct; +extern char *objc_destruct; +extern int DocOnly; + +// Structure for holding typemap parameters +// A typemap parameter consists of a single parameter (type + name) +// and an optional list of arguments corresponding to local variables. +// Has an optional link for building linked lists of parameter lists + +struct TMParm { + Parm *p; + ParmList *args; + TMParm *next; + TMParm() { + next = 0; + } +}; + +/* Global variables. Needs to be cleaned up */ + +#ifdef WRAP + + FILE *f_runtime; + FILE *f_header; // Some commonly used + FILE *f_wrappers; // FILE pointers + FILE *f_init; + FILE *f_input; + char InitName[256]; + char LibDir[512]; // Library directory + char **InitNames = 0; + int Status; + int TypeStrict; // Type checking strictness + int Verbose; + char category[256]; // Variables for documentation + char title[256]; + DocEntry *doc_entry = 0; // Current documentation entry + DocEntry *doctitle = 0; // First doc entry + DocEntry *doc_stack[256]; // Stack of documentation entries + CommentHandler *handler_stack[256]; // Stack of comment handlers + int doc_stack_top = 0; // Top of stack + + Language *lang; // Language method + Documentation *doc; // Documentation method + int Stat_func = 0; + int Stat_var = 0; + int Stat_const = 0; + int CPlusPlus = 0; + int ObjC = 0; + int ObjCClass = 0; + int AddMethods = 0; // AddMethods flag + int NewObject = 0; // NewObject flag + int Inline = 0; // Inline mode + int Stats = 0; + int IgnoreDoc = 0; // Ignore documentation mode + int ForceExtern = 0; // Force extern mode + int WrapExtern = 0; + int GenerateDefault = 0; // Generate default constructors + char *Config = 0; + int NoInclude = 0; + char *typemap_lang = 0; // Typemap name + int type_id = 0; // Type identifier + int error_count = 0; // Error count + char *ConfigFile = 0; + int DocOnly = 0; // Only produce documentation + +#endif + +/* Number of initialization names that can be used */ + +#define NI_NAMES 512 + +extern void type_undefined_check(void); + diff --git a/SWIG/Source/SWIG1.1/lang.cxx b/SWIG/Source/SWIG1.1/lang.cxx new file mode 100644 index 000000000..d1d722853 --- /dev/null +++ b/SWIG/Source/SWIG1.1/lang.cxx @@ -0,0 +1,621 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" +#include + + +// ----------------------------------------------------------------------- +// $Header$ +// +// lang.cxx +// +// This file contains some default methods for the SWIG language class. +// Default C++ handling is implemented here as well as a few utility functions. +// +// ----------------------------------------------------------------------- + + +// ----------------------------------------------------------------- +// void Language::set_init(char *iname) +// +// Called to make an initialization function by %init (obsolete) +// ----------------------------------------------------------------- + +void Language::set_init(char *iname) { + set_module(iname,0); +} + +// ----------------------------------------------------------------- +// void Language::create_command(char *cname, char *iname +// +// Method for adding a previous wrapped C function. +// ----------------------------------------------------------------- + +void Language::create_command(char *, char *) { + fprintf(stderr,"SWIG Warning. No command creation procedure defined.\n"); + fprintf(stderr,"C++ inheritance may not work correctly.\n"); +} + +// ----------------------------------------------------------------- +// void Language::add_native(char *targetlang, char *funcname) +// +// Method for adding a native function +// ----------------------------------------------------------------- + +void +Language::add_native(char *, char *funcname) { + + fprintf(stderr,"%s : Line %d. Adding native function %s not supported (ignored).\n", input_file, line_number, funcname); + +} + +static char *ClassName = 0; // This is the real name of the current class +static char *ClassRename = 0; // This is non-NULL if the class has been renamed +static char *ClassType = 0; // Type of class (ie. union, struct, class) + +// --------------------------------------------------------------------------------- +// void Language::cpp_open_class(char *classname, char *classrename, char *ctype, int strip) +// +// Open a new C++ class. +// +// INPUTS: +// classname = Real name of the C++ class +// classrename = 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 Language::cpp_open_class(char *classname, char *classrename, char *ctype, int strip) { + + // Copy the class name + + if (ClassName) delete ClassName; + ClassName = copy_string(classname); + + // Copy the class renaming + + if (ClassRename) delete ClassRename; + if (classrename) { + ClassRename = copy_string(classrename); + } else { + ClassRename = 0; // No renaming + } + + // Make the class type + + if (ClassType) delete ClassType; + ClassType = new char[strlen(ctype)+2]; + if (strip) ClassType[0] = 0; + else sprintf(ClassType,"%s ",ctype); + + if (doc_entry) { + doc_entry->usage = ""; + doc_entry->name = copy_string(classname); + doc_entry->usage << "class "; + if (ClassRename) doc_entry->usage << ClassRename; + else doc_entry->usage << ClassName; + doc_entry->cinfo << "created from " << ctype + << " " << classname; + } +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_close_class() +// +// Close the current class +// --------------------------------------------------------------------------------- + +void Language::cpp_close_class() { + + + // Doesn't really do anything +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_member_func(char *name, char *iname, DataType *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 Language::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) { + char cname[256]; // Name of the C function + char new_name[256]; + char *prefix; + + // Generate the C wrapper function name and interpreter name of this function + + // Set the classname prefix + if (ClassRename) { + prefix = ClassRename; + } else { + prefix = ClassName; + } + + // Generate the C wrapper name for this method + + if (AddMethods) { + char *bc = cplus_base_class(name); // Get base class name of this method + if (bc) + strcpy(cname, name_member(name,bc)); + else + strcpy(cname, name_member(name,ClassName)); + } else { + strcpy(cname, name_member(name,ClassName)); + } + + // Create the actual function name + + if (iname) { + strcpy(new_name, name_member(iname, prefix)); + } else { + strcpy(new_name, name_member(name,prefix)); + } + + // Now do a symbol table lookup on it : + + if (add_symbol(new_name, 0,0)) { + fprintf(stderr,"%s : Line %d. Function %s (member %s) multiply defined (2nd definition ignored).\n", + input_file, line_number, cname, name); + return; + } + + // Now produce the resulting wrapper function + if (doc_entry) { + doc_entry->cinfo << "Member : "; + } + cplus_emit_member_func(ClassName, ClassType, ClassRename, name, iname, t, l, AddMethods); +} + +// --------------------------------------------------------------------------------- +// void Language::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 Language::cpp_constructor(char *name, char *iname, ParmList *l) { + + char *prefix, *cname; + + if ((strcmp(name,ClassName)) && (!ObjCClass)) { + fprintf(stderr,"%s : Line %d. Function %s must have a return type.\n", + input_file, line_number, name); + return; + } + + // Set the prefix + + if (ClassRename) + prefix = ClassRename; + else + prefix = ClassName; + + if (iname) + cname = name_construct(iname); + else + cname = name_construct(prefix); + + // Add this function to the SWIG symbol table + + if (add_symbol(cname, 0,0)) { + fprintf(stderr,"%s : Line %d. Constructor %s multiply defined (2nd definition ignored).\n", + input_file, line_number, cname); + return; + } + + // Attach a note to the cinfo field. + + if (doc_entry) + doc_entry->cinfo << "Constructor: "; + + // Call our default method + + cplus_emit_constructor(ClassName, ClassType, ClassRename, name, iname, l, AddMethods); + +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_destructor(char *name, char *iname) +// +// Method for adding C++ member destructor +// +// INPUT: +// name - Name of the destructor (classname) +// iname - Renamed destructor +// +// --------------------------------------------------------------------------------- + +void Language::cpp_destructor(char *name, char *iname) { + + char *cname; + + if (ClassRename) + cname = name_destroy(ClassRename); + else + cname = name_destroy(ClassName); + + // Add this function to the SWIG symbol table + + if (add_symbol(cname, 0,0)) { + fprintf(stderr,"%s : Line %d. Destructor %s multiply defined (2nd definition ignored).\n", + input_file, line_number, cname); + return; + } + + + // Attach a note to the description + + if (doc_entry) + doc_entry->cinfo << "Destructor: "; + + // Call our default method + + cplus_emit_destructor(ClassName, ClassType, ClassRename, name, iname, AddMethods); + +} + +// --------------------------------------------------------------------------------- +// void Language::cleanup() +// +// Perform any necessary cleanup after reaching end of interface file +// --------------------------------------------------------------------------------- + +void Language::cpp_cleanup() { + + // This doesn't do anything (well, not be default) + +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_inherit(char **baseclass, int mode) +// +// Inherit attributes from given baseclass. +// +// INPUT: +// baseclass = NULL terminate list of baseclasses +// +// --------------------------------------------------------------------------------- + +void Language::cpp_inherit(char **baseclass, int mode) { + + extern void cplus_inherit_members(char *, int); + int i = 0; + + if (!baseclass) return; + while (baseclass[i]) { + cplus_inherit_members(baseclass[i],mode); + i++; + } +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_variable(char *name, char *iname, DataType *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 Language::cpp_variable(char *name, char *iname, DataType *t) { + char *prefix, *cname; + + // Set the class prefix + + if (ClassRename) { + prefix = ClassRename; + } else { + prefix = ClassName; + } + + if (iname) + cname = name_get(name_member(iname,prefix)); + else + cname = name_get(name_member(name,prefix)); + + // Check the symbol table + + if (add_symbol(cname,(DataType *) 0,(char *) 0)) { + fprintf(stderr,"%s : Line %d. Variable %s multiply defined (2nd definition ignored).\n", input_file, line_number, cname); + return; + } + + // Attach a c descriptor + + if (doc_entry) + doc_entry->cinfo << "Member data: "; + + // Create a function to set the value of the variable + + if (!(Status & STAT_READONLY)) { + cplus_emit_variable_set(ClassName, ClassType, ClassRename, name, iname, t, AddMethods); + // Add a new line to the documentation entry + if (doc_entry) doc_entry->usage << "\n"; + } + + // Create a function to get the value of a variable + + cplus_emit_variable_get(ClassName,ClassType, ClassRename, name, iname, t, AddMethods); + +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_static_func(char *name, char *iname, DataType *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 Language::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) { + + char *prefix; + char *mname; + char *cname; + + // Set the classname prefix + + if (ClassRename) + prefix = ClassRename; + else + prefix = ClassName; + + // Set the member function name + + if (iname) + mname = iname; + else + mname = name; + + cname = name_member(mname,prefix); + + // Now do a symbol table lookup on it : + + if (add_symbol(cname, 0,0)) { + if (ObjCClass) + fprintf(stderr,"%s : Line %d. class function %s multiply defined (2nd definition ignored).\n", + input_file, line_number, cname); + else + fprintf(stderr,"%s : Line %d. static function %s multiply defined (2nd definition ignored).\n", + input_file, line_number, cname); + return; + } + + if (doc_entry) { + if (ObjCClass) + doc_entry->cinfo << "Class method : "; + else + doc_entry->cinfo << "Static member : "; + } + + cplus_emit_static_func(ClassName,ClassType, ClassRename, name, iname, t, l, AddMethods); + +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_declare_const(char *name, char *iname, DataType *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 Language::cpp_declare_const(char *name, char *iname, DataType *type, char *value) +{ + + char *cname; + char mname[256]; + char *new_value; + char *prefix; + + // Set the classname prefix + + if (ClassRename) { + prefix = ClassRename; + } else { + prefix = ClassName; + } + + // Set the constant name + + if (iname) + cname = name_member(iname,prefix); + else + cname = name_member(name,prefix); + + // Now do a symbol table lookup on it : + + if (add_symbol(cname, 0,0)) { + fprintf(stderr,"%s : Line %d. Constant %s (member %s) multiply defined (2nd definition ignored).\n", + input_file, line_number, cname, name); + return; + } + + // Form correct C++ name + + sprintf(mname,"%s::%s",ClassName,name); + + // Declare a constant + if (!value) { + new_value = new char[strlen(ClassName)+strlen(name)+3]; + sprintf(new_value,"%s::%s",ClassName,name); + } else { + new_value = value; + } + + lang->declare_const(cname,cname,type, new_value); + + if (!value) { + delete new_value; + } +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_static_var(char *name, char *iname, DataType *t) +// +// Wrap a static C++ variable +// +// INPUT : +// name = name of the variable +// iname = interpreter name +// t = Datatype +// +// --------------------------------------------------------------------------------- + +void Language::cpp_static_var(char *name, char *iname, DataType *t) { + + char *cname; + char mname[256]; + char *prefix; + + // Set the classname prefix + + if (ClassRename) { + prefix = ClassRename; + } else { + prefix = ClassName; + } + + // Create the variable name + + if (iname) + cname = name_member(iname,prefix); + else + cname = name_member(name,prefix); + + // Now do a symbol table lookup on it : + + if (add_symbol(cname, 0,0)) { + fprintf(stderr,"%s : Line %d. Variable %s (member %s) multiply defined (2nd definition ignored).\n", + input_file, line_number, cname, name); + return; + } + + // Form correct C++ name + + sprintf(mname,"%s::%s",ClassName,name); + + if (doc_entry) + doc_entry->cinfo << "Static member : "; + + // Link with this variable + + lang->link_variable(mname,cname,t); +} + +// --------------------------------------------------------------------------------- +// void Language::cpp_class_decl(char *classtype, char *classrename, char *classname) +// +// A forward class declaration +// --------------------------------------------------------------------------------- + +void Language::cpp_class_decl(char *, char *, char *) { + + // Does nothing by default + +} + +// ----------------------------------------------------------------------------- +// void Language::cpp_pragma(Pragma *plist) +// +// Handler C++ pragmas +// ----------------------------------------------------------------------------- + +void Language::cpp_pragma(Pragma *) { + // Does nothing by default +} + +// --------------------------------------------------------------------------------- +// void Language::add_typedef(DataType *t, char *name) +// +// Process a typedef declaration. +// --------------------------------------------------------------------------------- + +void Language::add_typedef(DataType *, char *) { + +} + + +// --------------------------------------------------------------------------------- +// void Language::pragma(char *target, char *var, char *value) +// +// A pragma declaration +// --------------------------------------------------------------------------------- + +void Language::pragma(char *, char *, char *) { + + // Does nothing by default + +} + +// --------------------------------------------------------------------------------- +// void Language::import(char *filename) +// +// An import directive +// --------------------------------------------------------------------------------- + +void Language::import(char *) { + + // Does nothing by default + +} + + + + + + + + + diff --git a/SWIG/Source/SWIG1.1/latex.cxx b/SWIG/Source/SWIG1.1/latex.cxx new file mode 100644 index 000000000..37cb99835 --- /dev/null +++ b/SWIG/Source/SWIG1.1/latex.cxx @@ -0,0 +1,490 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * latex.c + * + * Latex specific functions for producing documentation. + * + ***********************************************************************/ + +#include "swig.h" +#include "latex.h" + +// ------------------------------------------------------------------- +// LATEX::LATEX() +// +// Create new LaTeX handler +// ------------------------------------------------------------------- + +LATEX::LATEX() { + sect_count = 0; + + tag_pagestyle = "\\pagestyle{headings}"; + tag_parindent = "0.0in"; + tag_textwidth = "6.5in"; + tag_documentstyle = "[11pt]{article}"; + tag_oddsidemargin = "0.0in"; + tag_title = "{\\Large \\bf : }"; + tag_preformat = "{\\small \\begin{verbatim}:\\end{verbatim}}"; + tag_usage = "{\\tt \\bf : }"; + tag_descrip = "\\\\\n\\makebox[0.5in]{}\\begin{minipage}[t]{6in}:\n\\end{minipage}\\\\\n"; + tag_text = ":\\\\"; + tag_cinfo = "{\\tt : }\\\\"; + tag_section = "\\section{:}"; + tag_subsection="\\subsection{:}"; + tag_subsubsection="\\subsubsection{:}"; +} + +// ------------------------------------------------------------------- +// char *start_tag(char *tag) { +// +// Returns the start of a tag +// ------------------------------------------------------------------- + +char *LATEX::start_tag(char *tag) { + static String stag; + char *c; + + stag = ""; + c = tag; + while ((*c) && (*c != ':')) { + stag << *c; + c++; + } + return stag.get(); +} + +// ------------------------------------------------------------------- +// char *end_tag(char *tag) { +// +// Returns the end of a tag +// ------------------------------------------------------------------- + +char *LATEX::end_tag(char *tag) { + static String etag; + char *c; + + etag = ""; + c = tag; + while ((*c) && (*c != ':')) { + c++; + } + if (*c) { + c++; + while (*c) { + etag << *c; + c++; + } + } + return etag.get(); +} + +// ------------------------------------------------------------------- +// LATEX::print_string(char *s, String &str) +// +// Dumps string s to str, but performs some LaTeX character replacements +// ------------------------------------------------------------------- + +void LATEX::print_string(char *s, String &str) { + + char *c; + c = s; + while (*c) { + switch(*c) { + case '*': + case '<': + case '>': + case '+': + case '=': + case '|': + str << "$" << *c << "$"; + break; + case '\\': + str << "\\\\"; + break; + case '_': + str << "\\_"; + break; + case '%': + str << "\\%"; + break; + case '$': + str << "\\$"; + break; + case '&': + str << "\\&"; + break; + case '#': + str << "\\#"; + break; + case '\n': + str << "\\\\\n"; + break; + default : + str << *c; + break; + } + c++; + } +} + +// -------------------------------------------------------------- +// LATEX::print_decl(DocEntry *) +// +// Print a documentation entry +// -------------------------------------------------------------- + +void LATEX::print_decl(DocEntry *de) { + + char *c; + + c = de->usage.get(); + + if (c) { + s_doc << start_tag(tag_usage); + print_string(c,s_doc); + s_doc << end_tag(tag_usage) << "\n"; + } + + // Check to see if there any information available + + if ((strlen(de->cinfo.get()) && de->print_info) || strlen(de->text.get())) { + + // There is additional information now. If we're in preformatting mode, + // we need to handle things differently + + s_doc << start_tag(tag_descrip) << "\n"; + + if (!de->format) { + // Verbatim mode + s_doc << start_tag(tag_preformat) << "\n"; + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << "[ " << c << " ]\n"; + } + } + c = de->text.get(); + if (strlen(c) > 0) { + s_doc << c; + } + s_doc << end_tag(tag_preformat) << "\n"; + } else { + // We are in format mode now + // We need to emit some stubs for the description format + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << start_tag(tag_cinfo) << "[ "; + print_string(c,s_doc); + s_doc << " ] " << end_tag(tag_cinfo) << "\n"; + } + } + // Print out descriptive text (if any). + c = de->text.get(); + if (strlen(c) > 0) { + s_doc << c << "\\\\\n"; + } + } + s_doc << end_tag(tag_descrip) << "\n"; + } else { + s_doc << "\\\\\n"; // No description available, move to next line + } +} + +// -------------------------------------------------------------- +// LATEX::print_text(DocEntry *de) +// +// Print out some text. We use verbatim mode because of formatting +// problems. +// -------------------------------------------------------------- + +void LATEX::print_text(DocEntry *de) { + char *c; + c = de->text.get(); + if (strlen(c) > 0) { + if (de->format) { + s_doc << start_tag(tag_text) << "\n"; + s_doc << c; + s_doc << end_tag(tag_text) << "\n\n"; + } else { + s_doc << start_tag(tag_preformat) << "\n"; + s_doc << c; + s_doc << end_tag(tag_preformat) << "\n\n"; + } + } +} + +void LATEX::title(DocEntry *de) { + char *c; + + c = de->usage.get(); + if (strlen(c) > 0) { + s_doc << start_tag(tag_title) << " "; + print_string(c,s_doc); + s_doc << end_tag(tag_title) << "\\\\\n"; + } + + // Print out any C annotation and descriptive text + // Check to see if there any information available + + if ((strlen(de->cinfo.get()) && de->print_info) || strlen(de->text.get())) { + + // There is additional information now. If we're in preformatting mode, + // we need to handle things differently + + if (!de->format) { + // Verbatim mode + s_doc << start_tag(tag_preformat) << "\n"; + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << "[ " << c << " ]\n"; + } + } + + c = de->text.get(); + if (strlen(c) > 0) { + s_doc << c; + } + s_doc << end_tag(tag_preformat) << "\n\n"; + } else { + // We are in format mode now + // We need to emit some stubs for the description format + s_doc << start_tag(tag_text); + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << start_tag(tag_cinfo) << "[ "; + print_string(c,s_doc); + s_doc << " ] " << end_tag(tag_cinfo) << "\n"; + } + } + // Print out descriptive text (if any). + c = de->text.get(); + if (strlen(c) > 0) { + s_doc << c; + } + s_doc << end_tag(tag_text); + } + } +} + +void LATEX::newsection(DocEntry *de,int sectnum) { + char *c; + char *tag; + + sect_num[sect_count] = sectnum; + sect_count++; + switch (sect_count) { + case 1: /* Section */ + tag = tag_section; + break; + case 2: /* Subsection */ + tag = tag_subsection; + break; + default: /* subsubsection */ + tag = tag_subsubsection; + break; + } + + s_doc << start_tag(tag); + c = de->usage.get(); + print_string(c,s_doc); + s_doc << end_tag(tag); + + + // Print out any C annotation and descriptive text + // Check to see if there any information available + + if ((strlen(de->cinfo.get()) && de->print_info) || strlen(de->text.get())) { + + // There is additional information now. If we're in preformatting mode, + // we need to handle things differently + + if (!de->format) { + // Verbatim mode + s_doc << start_tag(tag_preformat) << "\n"; + + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << "[ " << c << " ]\n"; + } + } + + c = de->text.get(); + if (strlen(c) > 0) { + s_doc << c; + } + s_doc << end_tag(tag_preformat) << "\n\n"; + } else { + // We are in format mode now + // We need to emit some stubs for the description format + + s_doc << start_tag(tag_text); + // If there is any C annotation, print that + if (de->print_info) { + c = de->cinfo.get(); + if (strlen(c) > 0) { + s_doc << start_tag(tag_cinfo) << "[ "; + print_string(c,s_doc); + s_doc << " ] " << end_tag(tag_cinfo) << "\n"; + } + } + // Print out descriptive text (if any). + c = de->text.get(); + if (strlen(c) > 0) { + s_doc << c; + } + s_doc << end_tag(tag_text); + } + } +} + + +void LATEX::endsection() { + if (sect_count > 0) sect_count--; +} + +void LATEX::separator() { +} + +void LATEX::init(char *filename) { + char f[256]; + + sprintf(f,"%s.tex",filename); + sprintf(fn,"%s",filename); + f_doc = fopen(f,"w"); + if (f_doc == NULL) { + fprintf(stderr, "Unable to open %s\n", fn); + SWIG_exit(1); + } +} + +void LATEX::close(void) { + + fprintf(f_doc,"\\documentstyle%s\n",tag_documentstyle); + fprintf(f_doc,"\\setlength{\\parindent}{%s}\n",tag_parindent); + fprintf(f_doc,"\\setlength{\\textwidth}{%s}\n",tag_textwidth); + fprintf(f_doc,"\\setlength{\\oddsidemargin}{%s}\n",tag_oddsidemargin); + fprintf(f_doc,"%s\n",tag_pagestyle); + fprintf(f_doc,"\\begin{document}\n"); + fprintf(f_doc,"%s\n",s_doc.get()); + fprintf(f_doc,"\\end{document}\n"); + fclose(f_doc); + if (Verbose) + fprintf(stderr,"Documentation written to %s.tex\n", fn); +} + +// ------------------------------------------------------------------- +// LATEX::style(char *name, char *value) +// +// Process style parameters +// ------------------------------------------------------------------- + +void LATEX::style(char *name, char *value) { + if (strcmp(name,"latex_title") == 0) { + if (value) + tag_title = copy_string(value); + } else if (strcmp(name,"latex_pagestyle") == 0) { + if (value) + tag_pagestyle = copy_string(value); + } else if (strcmp(name,"latex_section") == 0) { + if (value) + tag_section = copy_string(value); + } else if (strcmp(name,"latex_subsection") == 0) { + if (value) + tag_subsection = copy_string(value); + } else if (strcmp(name,"latex_subsubsection") == 0) { + if (value) + tag_subsubsection = copy_string(value); + } else if (strcmp(name,"latex_usage") == 0) { + if (value) + tag_usage = copy_string(value); + } else if (strcmp(name,"latex_descrip") == 0) { + if (value) + tag_descrip = copy_string(value); + } else if (strcmp(name,"latex_text") == 0) { + if (value) + tag_text = copy_string(value); + } else if (strcmp(name,"latex_cinfo") == 0) { + if (value) + tag_cinfo = copy_string(value); + } else if (strcmp(name,"latex_preformat") == 0) { + if (value) + tag_preformat = copy_string(value); + } else if (strcmp(name,"latex_parindent") == 0) { + if (value) + tag_parindent = copy_string(value); + } else if (strcmp(name,"latex_textwidth") == 0) { + if (value) + tag_textwidth = copy_string(value); + } else if (strcmp(name,"latex_documentstyle") == 0) { + if (value) + tag_documentstyle = copy_string(value); + } else if (strcmp(name,"latex_oddsidemargin") == 0) { + if (value) + tag_oddsidemargin = copy_string(value); + } +} + +// ------------------------------------------------------------------- +// LATEX::parse_args(int argc, char **argv) +// +// Parse command line options +// ------------------------------------------------------------------- + +static char *latex_usage = "\ +LATEX Documentation Options (available with -dlatex)\n\ + None available.\n\n"; + +void LATEX::parse_args(int argc, char **argv) { + int i; + + for (i = 0; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-help") == 0) { + fputs(latex_usage,stderr); + } + } + } +} + + + + + + + + + + + + + + diff --git a/SWIG/Source/SWIG1.1/latex.h b/SWIG/Source/SWIG1.1/latex.h new file mode 100644 index 000000000..6f65cc07b --- /dev/null +++ b/SWIG/Source/SWIG1.1/latex.h @@ -0,0 +1,79 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * latex.h + * + * Latex specific functions for producing documentation. + ***********************************************************************/ +class LATEX : public Documentation { +private: + FILE *f_doc; + String s_doc; + char fn[256]; + char *start_tag(char *); + char *end_tag(char *); + void print_string(char *s, String &str); + int sect_count; // Section counter + int sect_num[20]; // Section numbers + // Style parameters + + char *tag_parindent; + char *tag_textwidth; + char *tag_documentstyle; + char *tag_oddsidemargin; + char *tag_title; + char *tag_preformat; + char *tag_usage; + char *tag_descrip; + char *tag_text; + char *tag_cinfo; + char *tag_pagestyle; + char *tag_section; + char *tag_subsection; + char *tag_subsubsection; + +public: + LATEX(); + void parse_args(int argc, char **argv); + void title(DocEntry *de); + void newsection(DocEntry *de, int sectnum); + void endsection(); + void print_decl(DocEntry *de); + void print_text(DocEntry *de); + void separator(); + void init(char *filename); + void close(void); + void style(char *name, char *value); +}; + + + + + + + + + + + + + + + + + + diff --git a/SWIG/Source/SWIG1.1/main.cxx b/SWIG/Source/SWIG1.1/main.cxx new file mode 100644 index 000000000..67f52156b --- /dev/null +++ b/SWIG/Source/SWIG1.1/main.cxx @@ -0,0 +1,653 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * main.cxx + * + * The main program. + * + ***********************************************************************/ + +#define WRAP + +#include "internal.h" +#include "ascii.h" +#include "latex.h" +#include "html.h" +#include "nodoc.h" +#include +#include +#include +#include + +#include "swigcpp.h" + +class SwigException {}; + +static char *usage = "\ +\nDocumentation Options\n\ + -dascii - ASCII documentation.\n\ + -dhtml - HTML documentation.\n\ + -dlatex - LaTeX documentation.\n\ + -dnone - No documentation.\n\n\ +General Options\n\ + -c - Produce raw wrapper code (omit support code)\n\ + -c++ - Enable C++ processing\n\ + -ci - Check a file into the SWIG library\n\ + -co - Check a file out of the SWIG library\n\ + -d docfile - Set name of the documentation file.\n\ + -Dsymbol - Define a symbol (for conditional compilation)\n\ + -I - Look for SWIG files in \n\ + -l - Include SWIG library file.\n\ + -make_default - Create default constructors/destructors\n\ + -nocomment - Ignore all comments (for documentation).\n\ + -o outfile - Set name of the output file.\n\ + -objc - Enable Objective C processing\n\ + -stat - Print statistics\n\ + -strict n - Set pointer type-checking strictness\n\ + -swiglib - Report location of SWIG library and exit\n\ + -t typemap_file - Use a typemap file.\n\ + -v - Run in verbose mode\n\ + -version - Print SWIG version number\n\ + -help - This output.\n\n"; + +//----------------------------------------------------------------- +// main() +// +// Main program. Initializes the files and starts the parser. +//----------------------------------------------------------------- + +char infilename[256]; +char filename[256]; +char fn_cpp[256]; +char fn_header[256]; +char fn_wrapper[256]; +char fn_init[256]; +char output_dir[512]; +char fn_runtime[256]; + +#ifdef MACSWIG +FILE *swig_log; +#endif + +char *SwigLib; + +int SWIG_main(int argc, char *argv[], Language *l, Documentation *d) { + + int i; + char *c; + extern FILE *LEX_in; + extern void add_directory(char *); + extern char *get_time(); + char temp[512]; + char infile[512]; + + char *outfile_name = 0; + extern int add_iname(char *); + int help = 0; + int ignorecomments = 0; + int checkout = 0; + int checkin = 0; + int cpp_only = 0; + char *typemap_file = 0; + char *includefiles[256]; + int includecount = 0; + extern void check_suffix(char *); + extern void scanner_file(FILE *); + +#ifdef MACSWIG + try { +#endif + + f_wrappers = 0; + f_init = 0; + f_header = 0; + + lang = l; + doc = d; + Status = 0; + TypeStrict = 2; // Very strict type checking + Verbose = 0; + char *doc_file = 0; + + DataType::init_typedef(); // Initialize the type handler + + // Set up some default symbols (available in both SWIG interface files + // and C files) + + add_symbol("SWIG",0,0); // Define the SWIG symbol +#ifdef MACSWIG + add_symbol("SWIGMAC",0,0); +#endif +#ifdef SWIGWIN32 + add_symbol("SWIGWIN32",0,0); +#endif + + // Check for SWIG_LIB environment variable + + if ((c = getenv("SWIG_LIB")) == (char *) 0) { + sprintf(LibDir,"%s",SWIG_LIB); // Build up search paths + } else { + strcpy(LibDir,c); + } + + SwigLib = copy_string(LibDir); // Make a copy of the real library location +#ifdef MACSWIG + sprintf(temp,"%s:config", LibDir); + add_directory(temp); + add_directory(":swig_lib:config"); + add_directory(LibDir); + add_directory(":swig_lib"); +#else + sprintf(temp,"%s/config", LibDir); + add_directory(temp); + add_directory("./swig_lib/config"); + add_directory(LibDir); + add_directory("./swig_lib"); + SWIG_add_directory(temp); + SWIG_add_directory("./swig_lib/config"); + SWIG_add_directory(LibDir); + SWIG_add_directory("./swig_lib"); + sprintf(InitName,"init_wrap"); +#endif + + sprintf(InitName,"init_wrap"); + + // Initialize the preprocessor + SWIG_cpp_init(); + + // Get options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strncmp(argv[i],"-I",2) == 0) { + // Add a new directory search path + includefiles[includecount++] = copy_string(argv[i]+2); + mark_arg(i); + } else if (strncmp(argv[i],"-D",2) == 0) { + DOH *d = NewString(argv[i]+2); + String_replace(d,"="," ", DOH_REPLACE_ANY | DOH_REPLACE_FIRST); + SWIG_cpp_define(d,0); + // Create a symbol + add_symbol(argv[i]+2, (DataType *) 0, (char *) 0); + mark_arg(i); + } else if (strcmp(argv[i],"-strict") == 0) { + if (argv[i+1]) { + TypeStrict = atoi(argv[i+1]); + mark_arg(i); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if ((strcmp(argv[i],"-verbose") == 0) || (strcmp(argv[i],"-v") == 0)) { + Verbose = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-dascii") == 0) { + doc = new ASCII; + mark_arg(i); + } else if (strcmp(argv[i],"-dnone") == 0) { + doc = new NODOC; + mark_arg(i); + } else if (strcmp(argv[i],"-dhtml") == 0) { + doc = new HTML; + mark_arg(i); + } else if (strcmp(argv[i],"-dlatex") == 0) { + doc = new LATEX; + mark_arg(i); + } else if (strcmp(argv[i],"-nocomment") == 0) { + ignorecomments = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-stat") == 0) { + Stats=1; + mark_arg(i); + } else if (strcmp(argv[i],"-c++") == 0) { + CPlusPlus=1; + mark_arg(i); + } else if (strcmp(argv[i],"-objc") == 0) { + ObjC = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-c") == 0) { + NoInclude=1; + mark_arg(i); + } else if (strcmp(argv[i],"-make_default") == 0) { + GenerateDefault = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-swiglib") == 0) { + printf("%s\n", LibDir); + SWIG_exit(0); + } else if (strcmp(argv[i],"-o") == 0) { + mark_arg(i); + if (argv[i+1]) { + outfile_name = copy_string(argv[i+1]); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-d") == 0) { + mark_arg(i); + if (argv[i+1]) { + doc_file = copy_string(argv[i+1]); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-t") == 0) { + mark_arg(i); + if (argv[i+1]) { + typemap_file = copy_string(argv[i+1]); + mark_arg(i+1); + i++; + } else { + arg_error(); + } + } else if (strcmp(argv[i],"-version") == 0) { + fprintf(stderr,"\nSWIG Version %d.%d %s\n", SWIG_MAJOR_VERSION, + SWIG_MINOR_VERSION, SWIG_SPIN); + fprintf(stderr,"Copyright (c) 1995-98\n"); + fprintf(stderr,"University of Utah and the Regents of the University of California\n"); + fprintf(stderr,"\nCompiled with %s\n", SWIG_CC); + SWIG_exit(0); + } else if (strncmp(argv[i],"-l",2) == 0) { + // Add a new directory search path + library_add(argv[i]+2); + mark_arg(i); + } else if (strcmp(argv[i],"-co") == 0) { + checkout = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-ci") == 0) { + checkin = 1; + mark_arg(i); + } else if (strcmp(argv[i],"-help") == 0) { + fputs(usage,stderr); + mark_arg(i); + help = 1; + } + } + } + + while (includecount > 0) { + SWIG_add_directory(includefiles[includecount]); + add_directory(includefiles[--includecount]); + } + + // Create a new documentation handler + + if (doc == 0) doc = new ASCII; + + // Open up a comment handler + + comment_handler = new CommentHandler(); + comment_handler->parse_args(argc,argv); + if (ignorecomments) comment_handler->style("ignore",0); + + // Create a new documentation entry + + doctitle = new DocTitle("",0); + doctitle->parse_args(argc,argv); + doc_entry = doctitle; + + // Handle documentation module options + + doc->parse_args(argc,argv); + + // Parse language dependent options + + lang->parse_args(argc,argv); + + if (help) SWIG_exit(0); // Exit if we're in help mode + + // Check all of the options to make sure we're cool. + + check_options(); + + // If we made it this far, looks good. go for it.... + + // Create names of temporary files that are created + + sprintf(infilename,"%s", argv[argc-1]); + input_file = new char[strlen(infilename)+1]; + strcpy(input_file, infilename); + + // If the user has requested to check out a file, handle that + + if (checkout) { + int stat; + char *outfile = input_file; + if (outfile_name) + outfile = outfile_name; + stat = checkout_file(input_file,outfile); + if (!stat) { + fprintf(stderr,"%s checked out from the SWIG library\n",input_file); + } else { + FILE * f = fopen(input_file,"r"); + if (f) { + fprintf(stderr,"Unable to check-out %s. File already exists.\n", input_file); + fclose(f); + } else { + fprintf(stderr,"Unable to check-out %s\n", input_file); + } + } + } else if (checkin) { + // Try to check-in a file to the SWIG library + int stat; + char *outname = input_file; + if (outfile_name) + outname = outfile_name; + stat = checkin_file(SwigLib, LibDir, input_file, outname); + if (!stat) { + fprintf(stderr,"%s checked-in to %s/%s/%s\n", input_file, SwigLib, LibDir, outname); + } else { + fprintf(stderr,"Unable to check-in %s to %s/%s\n", input_file, SwigLib, LibDir); + } + } else { + doctitle->file = copy_string(input_file); + doctitle->line_number = -1000; + doctitle->end_line = -1000; + + // Check the suffix for a .c file. If so, we're going to + // declare everything we see as "extern" + + check_suffix(infilename); + + // Strip off suffix + + c = infilename + strlen(infilename); + while (c != infilename) { + if (*c == '.') { + *c = 0; + break; + } else { + c--; + } + } + + if (!outfile_name) { + sprintf(fn_runtime,"%s_wrap.c",infilename); + strcpy(infile,infilename); + strcpy(output_dir,""); + } else { + sprintf(fn_runtime,"%s",outfile_name); + // Try to identify the output directory + char *cc = outfile_name; + char *lastc = outfile_name; + while (*cc) { +#ifdef MACSWIG + if (*cc == ':') lastc = cc+1; +#else + if (*cc == '/') lastc = cc+1; +#endif + cc++; + } + cc = outfile_name; + char *dd = output_dir; + while (cc != lastc) { + *dd = *cc; + dd++; + cc++; + } + *dd = 0; + // Patch up the input filename + cc = infilename + strlen(infilename); + while (cc != infilename) { +#ifdef MACSWIG + if (*cc == ':') { + cc++; + break; + } +#else + if (*cc == '/') { + cc++; + break; + } +#endif + cc--; + } + strcpy(infile,cc); + } + + sprintf(fn_cpp,"%s%s_wrap.ii", output_dir, infile); + sprintf(fn_header,"%s%s_wrap.head", output_dir,infile); + sprintf(fn_wrapper,"%s%s_wrap.wrap",output_dir,infile); + sprintf(fn_init,"%s%s_wrap.init",output_dir,infile); + + sprintf(title,"%s", fn_runtime); + + // Open up files + + /* Preprocess. Ugh */ + + { + DOH *cpps; + DOH *ds = SWIG_include(input_file); + Seek(ds,0,SEEK_SET); + + } + + if ((f_input = fopen(input_file,"r")) == 0) { + // Okay. File wasn't found right away. Let's see if we can + // extract it from the SWIG library instead. + if ((checkout_file(input_file,input_file)) == -1) { + fprintf(stderr,"Unable to open %s\n", input_file); + SWIG_exit(0); + } else { + // Successfully checked out a file from the library, print a warning and + // continue + checkout = 1; + fprintf(stderr,"%s checked out from the SWIG library.\n",input_file); + if ((f_input = fopen(input_file,"r")) == 0) { + fprintf(stderr,"Unable to open %s\n", input_file); + SWIG_exit(0); + } + } + } + + // Add to the include list + + add_iname(infilename); + + // Initialize the scanner + + LEX_in = f_input; + scanner_file(LEX_in); + + printf("fn_cpp = %s\n", fn_cpp); + printf("fn_header = %s\n", fn_header); + printf("fn_wrapper = %s\n", fn_wrapper); + printf("fn_init = %s\n", fn_init); + + if ((f_runtime = fopen(fn_runtime,"w")) == 0) { + fprintf(stderr,"Unable to open %s\n", fn_runtime); + exit(0); + } + if((f_header = fopen(fn_header,"w")) == 0) { + fprintf(stderr,"Unable to open %s\n", fn_header); + exit(0); + } + if((f_wrappers = fopen(fn_wrapper,"w")) == 0) { + fprintf(stderr,"Unable to open %s\n",fn_wrapper); + exit(0); + } + if ((f_init = fopen(fn_init,"w")) == 0) { + fprintf(stderr,"Unable to open %s\n",fn_init); + exit(0); + } + + // Open up documentation + + if (doc_file) { + doc->init(doc_file); + } else { + doc_file = new char[strlen(infile)+strlen(output_dir)+8]; + sprintf(doc_file,"%s%s_wrap",output_dir,infile); + doc->init(doc_file); + } + + // Set up the typemap for handling new return strings + { + DataType *temp_t = new DataType(T_CHAR); + temp_t->is_pointer++; + if (CPlusPlus) + typemap_register("newfree",typemap_lang,temp_t,"","delete [] $source;\n",0); + else + typemap_register("newfree",typemap_lang,temp_t,"","free($source);\n",0); + + delete temp_t; + } + + // Define the __cplusplus symbol + if (CPlusPlus) + add_symbol("__cplusplus",0,0); + + + // Load up the typemap file if given + + if (typemap_file) { + if (include_file(typemap_file) == -1) { + fprintf(stderr,"Unable to locate typemap file %s. Aborting.\n", typemap_file); + SWIG_exit(1); + } + } + + // If in Objective-C mode. Load in a configuration file + + if (ObjC) { + // Add the 'id' object type as a void * + /* DataType *t = new DataType(T_VOID); + t->is_pointer = 1; + t->implicit_ptr = 0; + t->typedef_add("id"); + delete t; + */ + } + + // Pass control over to the specific language interpreter + + lang->parse(); + + fclose(f_header); + fclose(f_wrappers); + fclose(f_init); + + swig_append(fn_header, f_runtime); + swig_append(fn_wrapper,f_runtime); + swig_append(fn_init,f_runtime); + + fclose(f_runtime); + + // Print out documentation. Due to tree-like nature of documentation, + // printing out the title prints out everything. + + while(doctitle) { + doctitle->output(doc); + doctitle = doctitle->next; + } + + doc->close(); + + // Remove temporary files + + remove(fn_header); + remove(fn_wrapper); + remove(fn_init); + + // If only producing documentation, remove the wrapper file as well + + if (DocOnly) + remove(fn_runtime); + + // Check for undefined types that were used. + + if (Verbose) + type_undefined_check(); + + if (Stats) { + fprintf(stderr,"Wrapped %d functions\n", Stat_func); + fprintf(stderr,"Wrapped %d variables\n", Stat_var); + fprintf(stderr,"Wrapped %d constants\n", Stat_const); + type_undefined_check(); + } + + if (checkout) { + // File was checked out from the SWIG library. Remove it now + remove(input_file); + } + } +#ifdef MACSWIG + fclose(swig_log); + } catch (SwigException) { + fclose(swig_log); + } +#else + exit(error_count); +#endif + return(error_count); +} + +// -------------------------------------------------------------------------- +// SWIG_exit() +// +// Fatal parser error. Exit and cleanup +// -------------------------------------------------------------------------- + +void SWIG_exit(int) { + + if (f_wrappers) { + fclose(f_wrappers); + remove(fn_wrapper); + } + if (f_header) { + fclose(f_header); + remove(fn_header); + } + if (f_init) { + fclose(f_init); + remove(fn_init); + } + if (f_runtime) { + fclose(f_runtime); + remove(fn_runtime); + } +#ifndef MACSWIG + exit(1); +#else + throw SwigException(); +#endif +} + + +// -------------------------------------------------------------------------- +// swig_pragma(char *name, char *value) +// +// Handle pragma directives. Not many supported right now +// -------------------------------------------------------------------------- + +void swig_pragma(char *name, char *value) { + + if (strcmp(name,"make_default") == 0) { + GenerateDefault = 1; + } + if (strcmp(name,"no_default") == 0) { + GenerateDefault = 0; + } + if (strcmp(name,"objc_new") == 0) { + objc_construct = copy_string(value); + } + if (strcmp(name,"objc_delete") == 0) { + objc_destruct = copy_string(value); + } +} diff --git a/SWIG/Source/SWIG1.1/naming.cxx b/SWIG/Source/SWIG1.1/naming.cxx new file mode 100644 index 000000000..9fdda94aa --- /dev/null +++ b/SWIG/Source/SWIG1.1/naming.cxx @@ -0,0 +1,299 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" +#include +#include + +// -------------------------------------------------------------------------------- +// $Header$ +// +// naming.cxx +// +// SWIG naming service. +// +// This module provides universal naming services for manufacturing function names. +// All language modules use this so it provides a convenient centralized +// mechanism for producing names. +// -------------------------------------------------------------------------------- + +// Structure for holding names + +struct NamingScheme { + char *format; + int first; // Scoping information + int last; // Scoping information + NamingScheme *next; + NamingScheme(char *n) { + format = copy_string(n); + first = type_id; + last = INT_MAX; + next = 0; + }; +}; + +// Hash table containing naming data + +static Hash naming_hash; + +// Variable indicating naming scope + +static int naming_scope = -1; + +//----------------------------------------------------------------- +// make_wrap_name(char *s) +// +// Takes the name at src, and converts it into a syntactically +// valid identifier name. This is a hack to get the wrapper +// generator to support class member functions and other things. +// +// ie. We can define a function name as obj->foo(), +// but we'll need to call the wrapper function something like +// _wrap_obj__foo() +//----------------------------------------------------------------- + +void make_wrap_name(char *s) { + + char *c1 = s; + int i; + + for (i = 0; i < (int) strlen(s); i++, c1++) { + if(!isalnum(*c1)) *c1 = '_'; + } +} + +// -------------------------------------------------------------------------------- +// int name_scope(int scope) +// +// Set the scope variable. This is used to determine what naming scheme to +// use. Returns the current value of the scope. +// -------------------------------------------------------------------------------- + +int name_scope(int scope) { + int s = naming_scope; + naming_scope = scope; + return s; +} + +// -------------------------------------------------------------------------------- +// void name_register(char *method, char *format) +// +// Registers a new naming scheme. +// -------------------------------------------------------------------------------- + +void name_register(char *method, char *format) { + NamingScheme *ns, *nns; + + ns = (NamingScheme *) naming_hash.lookup(method); + if (ns) { + naming_hash.remove(method); + } + + nns = new NamingScheme(format); // Create a new naming scheme + if (ns) ns->last = type_id; + nns->next = ns; + + naming_hash.add(method,nns); +}; + +// -------------------------------------------------------------------------------- +// char *name_getformat(char *method) +// +// Looks up a naming scheme in the hash table. The scope of the name should have +// been set prior to calling this. If not set, we just use the last name entered. +// Returns the format string or NULL if no name has been set. +// -------------------------------------------------------------------------------- + +static char *name_getformat(char *method) { + + NamingScheme *ns; + int scope; + if (naming_scope == -1) scope = type_id; + else scope = naming_scope; + + ns = (NamingScheme *) naming_hash.lookup(method); + while (ns) { + if ((ns->first <= scope) && (scope < ns->last)) + return ns->format; + ns = ns->next; + } + return 0; +} + +// -------------------------------------------------------------------------------- +// char *name_wrapper(char *fname, char *prefix, int suppress) +// +// Returns the name of a wrapper function. The following variables are +// available : +// +// %f -> fname +// %p -> prefix +// %l -> language +// +// By default a wrapper function gets the name _wrap_prefixfname. +// +// -------------------------------------------------------------------------------- + +char *name_wrapper(char *fname, char *prefix, int suppress) { + static String fmt; + char *f; + + f = name_getformat("wrapper"); + if (!f) { + f = "_wrap_%p%f"; // Default wrapper name + } + fmt = f; + fmt.replace("%f",fname); + fmt.replace("%l",typemap_lang); + fmt.replace("%p",prefix); + if (!suppress) + make_wrap_name(fmt); + return fmt; +} + + +// -------------------------------------------------------------------------------- +// char *name_member(char *fname, char *classname, int suppress) +// +// Returns the name of a method function. The following variables are +// available : +// +// %f -> fname +// %c -> classname +// %l -> language +// +// By default, the name of a method is given as Classname_method. +// -------------------------------------------------------------------------------- + +char *name_member(char *fname, char *classname, int suppress) { + static String fmt; + char *f; + + f = name_getformat("member"); + if (!f) { + f = "%c_%f"; + } + fmt = f; + fmt.replace("%f",fname); + fmt.replace("%l",typemap_lang); + fmt.replace("%c",classname); + if (!suppress) + make_wrap_name(fmt); + return fmt; +} + + +// -------------------------------------------------------------------------------- +// char *name_get(char *vname, int suppress) +// +// Returns the name of the accessor function used to get a variable. +// +// %v -> variable name +// +// -------------------------------------------------------------------------------- + +char *name_get(char *vname, int suppress) { + static String fmt; + char *f; + + f = name_getformat("get"); + if (!f) { + f = "%v_get"; + } + fmt = f; + fmt.replace("%v",vname); + if (!suppress) + make_wrap_name(fmt); + return fmt; +} + +// -------------------------------------------------------------------------------- +// char *name_set(char *vname, int suppress) +// +// Returns the name of the accessor function used to set a variable. +// +// %v -> variable name +// -------------------------------------------------------------------------------- + +char *name_set(char *vname, int suppress) { + static String fmt; + char *f; + + f = name_getformat("set"); + if (!f) { + f = "%v_set"; + } + fmt = f; + fmt.replace("%v",vname); + if (!suppress) + make_wrap_name(fmt); + return fmt; +} + + +// -------------------------------------------------------------------------------- +// char *name_construct(char *classname, int suppress) +// +// Returns the name of the accessor function used to create an object. +// By default this is "new_classname" +// +// %c -> classname +// %l -> language +// +// -------------------------------------------------------------------------------- + +char *name_construct(char *classname, int suppress) { + static String fmt; + char *f; + + f = name_getformat("construct"); + if (!f) { + f = "new_%c"; + } + fmt = f; + fmt.replace("%l",typemap_lang); + fmt.replace("%c",classname); + if (!suppress) + make_wrap_name(fmt); + return fmt; +} + + +// -------------------------------------------------------------------------------- +// char *name_destroy(char *classname, int suppress) +// +// Returns the name of the accessor function used to destroy an object. +// By default this is "delete_classname" +// +// %c -> classname +// %l -> language +// +// -------------------------------------------------------------------------------- + +char *name_destroy(char *classname, int suppress) { + static String fmt; + char *f; + + f = name_getformat("destroy"); + if (!f) { + f = "delete_%c"; + } + fmt = f; + fmt.replace("%l",typemap_lang); + fmt.replace("%c",classname); + if (!suppress) + make_wrap_name(fmt); + return fmt; +} diff --git a/SWIG/Source/SWIG1.1/newdoc.cxx b/SWIG/Source/SWIG1.1/newdoc.cxx new file mode 100644 index 000000000..bc4347f98 --- /dev/null +++ b/SWIG/Source/SWIG1.1/newdoc.cxx @@ -0,0 +1,607 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * newdoc.cxx + * + * SWIG Documentation system. (2nd attempt) + * + * SWIG organizes documentation as a tree structure where each node is a + * documentation entry (DocEntry) of some kind. To generate documentation, + * we simply traverse the tree and call output methods. + * + * A sample documentation tree looks something like the following : + * + * TITLE ----> SECTION 1 ----> func1 + * ----> func2 + * ----> func3 + * ----> class ---> func1 + * ---> func2 + * ---> var1 + * ----> func4 + * + * ----> SECTION 2 ----> func1 + * ----> var1 + * + * and so on. + * + * This structure makes it possible to organize C++ classes and more + * complicated structures. Hopefully this will provide enough structure + * for later versions of SWIG. + * + *************************************************************************/ + +#include "internal.h" +#include + +extern char *get_time(); +static char *last_name = 0; + +DocEntry *DocEntry::dead_entries = 0; + +// Utility function for converting a string to upper case + +static void str_toupper(char *str) { + char *c; + c = str; + while (*c) { + *c = toupper(*c); + c++; + } +} + +// -------------------------------------------------------------------- +// DocEntry::~DocEntry +// +// Destroy a documentation entry. Destroys this entry and all of +// its children. +// -------------------------------------------------------------------- + +DocEntry::~DocEntry() { + DocEntry *de, *de1; + + if (name) delete name; + + // Now kill all of the children (well, figuratively speaking) + + de = child; + while (de) { + de1 = de->next; + delete de; + de = de1; + } +} + +// -------------------------------------------------------------------- +// void DocEntry::sort_children() +// +// Sort children by name (not height). This function gathers all +// of the children up into an array of pointers. Then we do an +// insertion sort on it and place the children back in order. +// -------------------------------------------------------------------- + +void DocEntry::sort_children() { + + int count = 0; + int i,j; + DocEntry *d; + DocEntry **list; + DocEntry *v; + + if (!child) return; // Nothing to sort + + d = child; + while (d) { + count++; + d = d->next; + } + + // allocate a temporary array for sorting everything + + list = new DocEntry *[count+2]; + + // Now put pointers into list + + d = child; + i = 0; + while (d) { + list[i] = d; + d = d->next; + i++; + } + + // Do an insertion sort by name + + for (i = 1; i < count; i++) { + v = list[i]; + j = i; + while((j > 0) && (strcmp(list[j-1]->name,v->name) > 0)) { + list[j] = list[j-1]; + j--; + } + list[j] = v; + } + + // Now, we're going to reorganize the children in order + + list[count] = 0; + child = list[0]; // Our child is the first one in the list + d = child; + for (i = 0; i < count; i++) { + d->next = list[i+1]; + d = d->next; + } + delete list; +} + +// -------------------------------------------------------------------- +// void DocEntry::output() +// +// Output this entry +// -------------------------------------------------------------------- + +void DocEntry::output(Documentation *) { + fprintf(stderr,"SWIG (internal) : No output method defined for DocEntry.\n"); +} + +// -------------------------------------------------------------------- +// DocEntry::add(DocEntry *de) +// +// Adds a new DocEntry as a sibling. Basically we just walk down the +// linked list and append ourselves to the end. The documentation +// Entry we're adding may, in fact, have siblings too, but this function +// Should still work. +// -------------------------------------------------------------------- + +void DocEntry::add(DocEntry *de) { + DocEntry *d,*d1; + d = next; + d1 = this; + while (d) { + d1 = d; + d = d->next; + } + d1->next = de; + de->previous = d1; // Set up the previous list member +} + + +// -------------------------------------------------------------------- +// DocEntry::addchild(DocEntry *de) +// +// Adds a new DocEntry as a child. If we're in Ignore mode, the +// documentation entry is still created, but we simply abandon it. +// -------------------------------------------------------------------- + +void DocEntry::addchild(DocEntry *de) { + if (!IgnoreDoc) { + if (child) child->add(de); + else child = de; + } else { + if (dead_entries) dead_entries->add(de); + else dead_entries = de; + } +} + +// ------------------------------------------------------------------- +// DocEntry::remove() +// +// Removes a documentation entry from the tree and places it on +// the dead_entries list +// ------------------------------------------------------------------- + +void DocEntry::remove() { + + if (previous) { + if (next) + previous->next = next; // Take out of the linked list + else + previous->next = 0; + } else { // Make sure our parent isn't pointing to us + if (parent) + parent->child = next; + } + + previous = 0; + next = 0; + + if (!dead_entries) dead_entries = this; + else dead_entries->add(this); + +} + +// ------------------------------------------------------------------- +// void DocEntry::style(char *name, char *value) +// +// Set style parameters of a documentation entry +// ------------------------------------------------------------------- + +void DocEntry::style(char *pname, char *) { + if (strcmp(pname,"sort") == 0) { + sorted = 1; + } else if (strcmp(pname,"nosort") == 0) { + sorted = 0; + } else if (strcmp(pname,"info") == 0) { + print_info = 1; + } else if (strcmp(pname,"noinfo") == 0) { + print_info = 0; + } else if (strcmp(pname,"pre") == 0) { + format = 0; + } else if (strcmp(pname,"format") == 0) { + format = 1; + } +} + +// ------------------------------------------------------------------- +// void DocEntry::parse_args(int argc, char **argv) +// +// Take command line options and process them. This really only +// applies to the top-level documentation entry. +// ------------------------------------------------------------------- + +static char *doc_usage = "\ +Documentation Processing : \n\ + -Sformat - Reformat comment text\n\ + -Sinfo - Print C formatting information (the default)\n\ + -Snoinfo - Omit C formatting information.\n\ + -Snosort - Print everything in order (the default)\n\ + -Spre - Assume comments are pre-formatted (the default)\n\ + -Ssort - Sort documentation alphabetically\n\n"; + +void DocEntry::parse_args(int argc, char **argv) { + int i; + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-Ssort") == 0) { + this->style("sort",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Snosort") == 0) { + this->style("nosort",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Sinfo") == 0) { + this->style("info",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Snoinfo") == 0) { + this->style("noinfo",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Spre") == 0) { + this->style("pre",0); + mark_arg(i); + } else if (strcmp(argv[i],"-Sformat") == 0) { + this->style("format",0); + mark_arg(i); + } else if (strcmp(argv[i],"-help") == 0) { + fputs(doc_usage,stderr); + } + } + } +} + + +// ------------------------------------------------------------------- +// DocTitle::DocTitle(char *title, DocEntry *_parent); +// +// Create a new title documentation entry. The name of the entry +// is the title. +// +// The body text is optional, but may be filled in with a description +// as well. +// ------------------------------------------------------------------- + +DocTitle::DocTitle(char *title, DocEntry *_parent) { + name = copy_string(title); + str_toupper(name); + parent = _parent; + child = 0; + next = 0; + previous = 0; + usage << title << "\n"; + counter = 1; + is_separator = 1; + line_number = ::start_line; + end_line = ::line_number; + file = copy_string(input_file); + if (_parent) { + sorted = _parent->sorted; + format = _parent->format; + print_info = _parent->print_info; + } else { + sorted = SWIGDEFAULT_SORT; + format = SWIGDEFAULT_FORMAT; + print_info = SWIGDEFAULT_INFO; + } + comment_handler->set_entry(this); + if (last_name) delete last_name; + last_name = 0; +} +// -------------------------------------------------------------------- +// DocTitle::output(Documentation *d) +// +// Output a title to the Documentation module +// -------------------------------------------------------------------- + +void DocTitle::output(Documentation *d) { + DocEntry *de; + + d->title(this); + if (sorted) { + sort_children(); + } + + // Now output my children + + de = child; + while (de) { + de->output(d); + de = de->next; + } +} + +// ------------------------------------------------------------------- +// DocSection::DocSection(char *section, DocEntry *_parent); +// +// Create a new documentation section. The name and description is +// set to the name of the section. The text field is optional +// but could contain a more complete description. +// +// The sorted field indicates whether members of this section are +// sorted or not. +// ------------------------------------------------------------------- + +DocSection::DocSection(char *section, DocEntry *_parent) { + name = copy_string(section); + str_toupper(name); + parent = _parent; + child = 0; + next = 0; + previous = 0; + usage << section; + counter = 1; + is_separator = 1; + if (_parent) _parent->addchild(this); + line_number = ::start_line; + end_line = ::line_number; + file = copy_string(input_file); + if (_parent) { + sorted = _parent->sorted; + format = _parent->format; + print_info = _parent->print_info; + } else { + sorted = SWIGDEFAULT_SORT; + format = SWIGDEFAULT_FORMAT; + print_info = SWIGDEFAULT_INFO; + } + comment_handler->set_entry(this); + if (last_name) delete last_name; + last_name = 0; +} + +// -------------------------------------------------------------------- +// DocSection::output(Documentation *d) +// +// Output a section to the documentation module +// -------------------------------------------------------------------- + +void DocSection::output(Documentation *d) { + DocEntry *de; + + // Make a new section + + d->newsection(this,this->parent->counter++); // Make a new section + + // Sort the children if necessary + + if (sorted) { + sort_children(); + } + + // Now output my children + + de = child; + while (de) { + de->output(d); + de = de->next; + } + + // End this section + + d->endsection(); + +} + + +// ------------------------------------------------------------------- +// DocDecl::DocDecl(char *fname, DocEntry *_parent); +// +// Create documentation for a function declaration. +// ------------------------------------------------------------------- + +DocDecl::DocDecl(char *fname, DocEntry *_parent) { + name = copy_string(fname); + str_toupper(name); + parent = _parent; + child = 0; + next = 0; + previous = 0; + is_separator = 0; + if (_parent) _parent->addchild(this); + line_number = ::start_line; + end_line = ::line_number; + file = copy_string(input_file); + if (_parent) { + sorted = _parent->sorted; + format = _parent->format; + print_info = _parent->print_info; + } else { + sorted = SWIGDEFAULT_SORT; + format = SWIGDEFAULT_FORMAT; + print_info = SWIGDEFAULT_INFO; + } + comment_handler->set_entry(this); + if (last_name) delete last_name; + last_name = copy_string(name); +} + + +// -------------------------------------------------------------------- +// DocDecl::DocDecl(DocEntry *de, DocEntry *_parent) +// +// Make a new declaration entry, but copy attributes from someone else +// -------------------------------------------------------------------- + +DocDecl::DocDecl(DocEntry *de, DocEntry *_parent) { + name = copy_string(de->name); + usage = de->usage.get(); + cinfo = de->cinfo.get(); + text = de->text.get(); + line_number = de->line_number; + end_line = de->end_line; + file = copy_string(de->file); + print_info = de->print_info; + format = de->format; + if (_parent) { + _parent->addchild(this); + } +} + +// -------------------------------------------------------------------- +// DocDecl::output(Documentation *d) +// +// Output a function to the documentation module +// -------------------------------------------------------------------- + +void DocDecl::output(Documentation *d) { + d->print_decl(this); +} + +// ------------------------------------------------------------------- +// DocClass::DocClass(char *classname, DocEntry *_parent); +// +// Create a new class section. Classes are created as funny sorts of +// sections. +// +// The sorted field indicates whether members of this section are +// sorted or not. +// ------------------------------------------------------------------- + +DocClass::DocClass(char *classname, DocEntry *_parent) { + name = copy_string(classname); + str_toupper(name); + parent = _parent; + child = 0; + next = 0; + previous = 0; + usage << classname<< "\n"; + counter = 1; + is_separator = 1; + if (_parent) _parent->addchild(this); + line_number = ::start_line; + end_line = ::line_number; + file = copy_string(input_file); + if (_parent) { + sorted = _parent->sorted; + format = _parent->format; + print_info = _parent->print_info; + } else { + sorted = SWIGDEFAULT_SORT; + format = SWIGDEFAULT_FORMAT; + print_info = SWIGDEFAULT_INFO; + } + comment_handler->set_entry(this); + if (last_name) delete last_name; + last_name = copy_string(name); + +} + +// -------------------------------------------------------------------- +// DocClass::output(Documentation *d) +// +// Output a section to the documentation module +// -------------------------------------------------------------------- + +void DocClass::output(Documentation *d) { + DocEntry *de; + + // Make a new section + + d->newsection(this,this->parent->counter++); // Make a subsection for this + + // Sort the children if necessary + + if (sorted) { + sort_children(); + } + + // Now output my children + + de = child; + while (de) { + de->output(d); + de = de->next; + } + + // End this section + + d->endsection(); + + // We now check to see if the next thing is a separator. If not, we'll + // emit a separator + + if (next) { + if (!next->is_separator) + d->separator(); + } +} + +// ------------------------------------------------------------------- +// DocText::DocText(char *_text, DocEntry *_parent); +// +// Create documentation for a function declaration. +// ------------------------------------------------------------------- + +DocText::DocText(char *_text, DocEntry *_parent) { + if (!last_name) + name = copy_string(""); // There is no name for text + else + name = copy_string(last_name); + parent = _parent; + child = 0; + next = 0; + previous = 0; + text << _text; + is_separator = 0; + if (_parent) _parent->addchild(this); + if (_parent) { + sorted = _parent->sorted; + format = _parent->format; + print_info = _parent->print_info; + } else { + sorted = SWIGDEFAULT_SORT; + format = SWIGDEFAULT_FORMAT; + print_info = SWIGDEFAULT_INFO; + } +} + +// -------------------------------------------------------------------- +// DocText::output(Documentation *d) +// +// Output a function to the documentation module +// -------------------------------------------------------------------- + +void DocText::output(Documentation *d) { + d->print_text(this); +} + diff --git a/SWIG/Source/SWIG1.1/nodoc.h b/SWIG/Source/SWIG1.1/nodoc.h new file mode 100644 index 000000000..086e5dc71 --- /dev/null +++ b/SWIG/Source/SWIG1.1/nodoc.h @@ -0,0 +1,54 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * nodoc.h + * + * A null documentation header. Does nothing. + ***********************************************************************/ + +class NODOC : public Documentation { +private: +public: + NODOC() { }; + void parse_args(int, char **) { }; + void title(DocEntry *) { }; + void newsection(DocEntry *, int) { }; + void endsection() { }; + void print_decl(DocEntry *) { }; + void print_text(DocEntry *) { }; + void separator() { }; + void init(char *) { }; + void close(void) { }; + void style(char *, char *) { }; +}; + + + + + + + + + + + + + + + + + diff --git a/SWIG/Source/SWIG1.1/parms.cxx b/SWIG/Source/SWIG1.1/parms.cxx new file mode 100644 index 000000000..a23b831c0 --- /dev/null +++ b/SWIG/Source/SWIG1.1/parms.cxx @@ -0,0 +1,478 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/* ------------------------------------------------------------------------ + $Header$ + + parms.cxx + + This file is used to manage function parameters and parameter lists. + Rewritten (10/27) to solve a bunch of problems with memory management + and proper cleanup of things. + ------------------------------------------------------------------------ */ + +#include "swig.h" + +// ------------------------------------------------------------------------ +// Parm::Parm(DataType *type, char *n) +// +// Create a new parameter from datatype 'type' and name 'n'. +// Copies will be made of type and n, unless they aren't specified. +// ------------------------------------------------------------------------ + +Parm::Parm(DataType *type, char *n) { + if (type) { + t = new DataType(type); + } else { + t = 0; + } + name = copy_string(n); + call_type = 0; + defvalue = 0; + ignore = 0; + objc_separator = 0; +} + +// ------------------------------------------------------------------------ +// Parm::Parm(Parm *p) +// +// Make a copy of a parameter +// ------------------------------------------------------------------------ + +Parm::Parm(Parm *p) { + if (p->t) t = new DataType(p->t); + name = copy_string(p->name); + call_type = p->call_type; + defvalue = copy_string(p->defvalue); + ignore = p->ignore; + objc_separator = copy_string(p->objc_separator); +} + +// ------------------------------------------------------------------------ +// Parm::~Parm() +// +// Destroy a parameter +// ------------------------------------------------------------------------ + +Parm::~Parm() { + if (t) delete t; + if (name) delete name; + if (defvalue) delete defvalue; + if (objc_separator) delete objc_separator; +} + +/******************************************************************** + class ParmList + + These functions are used to manipulate lists of parameters + ********************************************************************/ + +// ------------------------------------------------------------------ +// ParmList::ParmList() +// +// Create a new (empty) parameter list +// ------------------------------------------------------------------ + +ParmList::ParmList() { + + nparms = 0; + maxparms = MAXPARMS; + parms = new Parm *[maxparms]; // Create an array of parms + for (int i = 0; i < MAXPARMS; i++) + parms[i] = (Parm *) 0; +} + +// ------------------------------------------------------------------ +// ParmList::ParmList(ParmList *l) +// +// Make a copy of parameter list +// ------------------------------------------------------------------ + +ParmList::ParmList(ParmList *l) { + int i; + + if (l) { + nparms = l->nparms; + maxparms = l->maxparms; + parms = new Parm *[maxparms]; + + for (i = 0; i < maxparms; i++) { + if (l->parms[i]) + parms[i] = new Parm(l->parms[i]); + else + parms[i] = 0; + } + + } else { + nparms = 0; + maxparms = MAXPARMS; + parms = new Parm *[maxparms]; // Create an array of parms + + for (i = 0; i < MAXPARMS; i++) + parms[i] = (Parm *) 0; + } +} + +// ------------------------------------------------------------------ +// ParmList::~ParmList() +// +// Delete a parameter list +// ------------------------------------------------------------------ + +ParmList::~ParmList() { + for (int i = 0; i < maxparms; i++) { + if (parms[i]) delete parms[i]; + } +} + + +// ------------------------------------------------------------------ +// void ParmList::moreparms() (PRIVATE) +// +// Doubles the amount of parameter memory available. +// ------------------------------------------------------------------ + +void ParmList::moreparms() { + Parm **newparms; + int i; + + newparms = new Parm *[maxparms*2]; + for (i = 0; i < 2*maxparms; i++) + newparms[i] = (Parm *) 0; + for (i = 0; i < maxparms; i++) { + newparms[i] = parms[i]; + } + maxparms = 2*maxparms; + delete parms; + parms = newparms; +} + +// ------------------------------------------------------------------ +// void ParmList::append(Parm *p) +// +// Add a new parameter to the end of a parameter list +// ------------------------------------------------------------------ + +void ParmList::append(Parm *p) { + + if (nparms == maxparms) moreparms(); + + // Add parm onto the end + + parms[nparms] = new Parm(p); + nparms++; +} + +// ------------------------------------------------------------------ +// void ParmList::insert(Parm *p, int pos) +// +// Inserts a parameter at position pos. Parameters are inserted +// *before* any existing parameter at position pos. +// ------------------------------------------------------------------ + +void ParmList::insert(Parm *p, int pos) { + + // If pos is out of range, we'd better fix it + + if (pos < 0) pos = 0; + if (pos > nparms) pos = nparms; + + // If insertion is going to need more memory, take care of that now + + if (nparms >= maxparms) moreparms(); + + // Now shift all of the existing parms to the right + + for (int i = nparms; i > pos; i--) { + parms[i] = parms[i-1]; + } + + // Set new parameter + + parms[pos] = new Parm(p); + nparms++; + +} + +// ------------------------------------------------------------------ +// void ParmList::del(int pos) +// +// Deletes the parameter at position pos. +// ------------------------------------------------------------------ + +void ParmList::del(int pos) { + + if (nparms <= 0) return; + if (pos < 0) pos = 0; + if (pos >= nparms) pos = nparms-1; + + // Delete the parameter (if it exists) + + if (parms[pos]) delete parms[pos]; + + // Now slide all of the parameters to the left + + for (int i = pos; i < nparms-1; i++) { + parms[i] = parms[i+1]; + } + nparms--; + +} + +// ------------------------------------------------------------------ +// Parm *ParmList::get(int pos) +// +// Gets the parameter at location pos. Returns 0 if invalid +// position. +// ------------------------------------------------------------------ + +Parm *ParmList::get(int pos) { + + if ((pos < 0) || (pos >= nparms)) return 0; + return parms[pos]; +} + +// ------------------------------------------------------------------ +// int ParmList::numopt() +// +// Gets the number of optional arguments. +// ------------------------------------------------------------------ +int ParmList::numopt() { + int n = 0; + int state = 0; + + for (int i = 0; i < nparms; i++) { + if (parms[i]->defvalue) { + n++; + state = 1; + } else if (typemap_check("default",typemap_lang,parms[i]->t,parms[i]->name)) { + n++; + state = 1; + } else if (typemap_check("ignore",typemap_lang,parms[i]->t,parms[i]->name)) { + n++; + } else if (typemap_check("build",typemap_lang,parms[i]->t,parms[i]->name)) { + n++; + } else { + if (state) { + fprintf(stderr,"%s : Line %d. Argument %d must have a default value!\n", input_file,line_number,i+1); + } + } + } + return n; +} + +// ------------------------------------------------------------------ +// int ParmList::numarg() +// +// Gets the number of arguments +// ------------------------------------------------------------------ +int ParmList::numarg() { + int n = 0; + + for (int i = 0; i < nparms; i++) { + if (!parms[i]->ignore) + n++; + } + return n; +} + +// ------------------------------------------------------------------ +// Parm &ParmList::operator[](int n) +// +// Returns parameter n in the parameter list. May generate +// an error if that parameter is out of range. +// ------------------------------------------------------------------ + +Parm &ParmList::operator[](int n) { + + if ((n < 0) || (n >= nparms)) { + fprintf(stderr,"ParmList : Fatal error. subscript out of range in ParmList.operator[]\n"); + SWIG_exit(1); + } + + return *parms[n]; +} + +// --------------------------------------------------------------------- +// Parm * ParmList::get_first() +// +// Returns the first item on a parameter list. +// --------------------------------------------------------------------- + +Parm *ParmList::get_first() { + current_parm = 0; + if (nparms > 0) return parms[current_parm++]; + else return (Parm *) 0; +} + +// ---------------------------------------------------------------------- +// Parm *ParmList::get_next() +// +// Returns the next item on the parameter list. +// ---------------------------------------------------------------------- + +Parm * ParmList::get_next() { + if (current_parm >= nparms) return 0; + else return parms[current_parm++]; +} + +// --------------------------------------------------------------------- +// void ParmList::print_types(FILE *f) +// +// Prints a comma separated list of all of the parameter types. +// This is for generating valid C prototypes. Has to do some +// manipulation of pointer types depending on how the call_type +// variable has been set. +// ---------------------------------------------------------------------- + +void ParmList::print_types(FILE *f) { + + int is_pointer; + int pn; + pn = 0; + while(pn < nparms) { + is_pointer = parms[pn]->t->is_pointer; + if (parms[pn]->t->is_reference) { + if (parms[pn]->t->is_pointer) { + parms[pn]->t->is_pointer--; + fprintf(f,"%s&", parms[pn]->t->print_real()); + parms[pn]->t->is_pointer++; + } else { + fprintf(f,"%s&", parms[pn]->t->print_real()); + } + } else { + if (parms[pn]->call_type & CALL_VALUE) parms[pn]->t->is_pointer++; + if (parms[pn]->call_type & CALL_REFERENCE) parms[pn]->t->is_pointer--; + fprintf(f,"%s", parms[pn]->t->print_real()); + parms[pn]->t->is_pointer = is_pointer; + } + pn++; + if (pn < nparms) + fprintf(f,","); + } +} + + +// --------------------------------------------------------------------- +// void ParmList::print_types(String &f) +// +// Generates a comma separated list of function types. Is used in +// C++ code generation when generating hash keys and for function overloading. +// ---------------------------------------------------------------------- + +void ParmList::print_types(String &f) { + + int is_pointer; + int pn; + pn = 0; + while(pn < nparms) { + is_pointer = parms[pn]->t->is_pointer; + if (parms[pn]->t->is_reference) { + if (parms[pn]->t->is_pointer) { + parms[pn]->t->is_pointer--; + f << parms[pn]->t->print_real() << "&"; + parms[pn]->t->is_pointer++; + } else { + f << parms[pn]->t->print_real() << "&"; + } + } else { + if (parms[pn]->call_type & CALL_VALUE) parms[pn]->t->is_pointer++; + if (parms[pn]->call_type & CALL_REFERENCE) parms[pn]->t->is_pointer--; + f << parms[pn]->t->print_real(); + parms[pn]->t->is_pointer = is_pointer; + } + pn++; + if (pn < nparms) + f << ","; + } +} + + +// --------------------------------------------------------------------- +// void ParmList::print_args(FILE *f) +// +// Prints a comma separated list of all of the parameter arguments. +// ---------------------------------------------------------------------- + +void ParmList::print_args(FILE *f) { + + int is_pointer; + int pn; + pn = 0; + while(pn < nparms) { + is_pointer = parms[pn]->t->is_pointer; + if (parms[pn]->t->is_reference) { + if (parms[pn]->t->is_pointer) { + parms[pn]->t->is_pointer--; + fprintf(f,"%s&", parms[pn]->t->print_full()); + parms[pn]->t->is_pointer++; + } else { + fprintf(f,"%s&", parms[pn]->t->print_full()); + } + } else { + if (parms[pn]->call_type & CALL_VALUE) parms[pn]->t->is_pointer++; + if (parms[pn]->call_type & CALL_REFERENCE) parms[pn]->t->is_pointer--; + fprintf(f,"%s", parms[pn]->t->print_full()); + parms[pn]->t->is_pointer = is_pointer; + } + fprintf(f,"%s",parms[pn]->name); + pn++; + if (pn < nparms) + fprintf(f,","); + } +} + +// ------------------------------------------------------------------- +// int check_defined() +// +// Checks to see if all of the datatypes are defined. +// ------------------------------------------------------------------- + +int ParmList::check_defined() { + int a = 0; + int i; + for (i = 0; i < nparms; i++) { + if (parms[i]) { + a+=parms[i]->t->check_defined(); + } + } + if (a) return 1; + else return 0; +} + + +// ------------------------------------------------------------------- +// void ParmList::sub_parmnames(String &s) +// +// Given a string, this function substitutes all of the parameter +// names with their internal representation. Used in very special +// kinds of typemaps. +// ------------------------------------------------------------------- + +void ParmList::sub_parmnames(String &s) { + Parm *p; + extern char *emit_local(int i); + for (int i = 0; i < nparms; i++) { + p = get(i); + if (strlen(p->name) > 0) { + s.replaceid(p->name, emit_local(i)); + } + } +} + + + + + diff --git a/SWIG/Source/SWIG1.1/parser.y b/SWIG/Source/SWIG1.1/parser.y new file mode 100644 index 000000000..0aba5b670 --- /dev/null +++ b/SWIG/Source/SWIG1.1/parser.y @@ -0,0 +1,4157 @@ +%{ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * parser.y + * + * YACC parser for parsing function declarations. + * + * *** DISCLAIMER *** + * + * This is the most ugly, incredibly henious, and completely unintelligible + * file in SWIG. While it started out simple, it has grown into a + * monster that is almost unmaintainable. A complete parser rewrite is + * currently in progress that should make this file about 1/4 the size + * that it is now. Needless to say, don't modify this file or even look + * at it for that matter! + ***********************************************************************/ + +#define yylex yylex + +extern "C" int yylex(); +void yyerror (char *s); + +extern int line_number; +extern int start_line; +extern void skip_brace(void); +extern void skip_define(void); +extern void skip_decl(void); +extern int skip_cond(int); +extern void skip_to_end(void); +extern void skip_template(void); +extern void scanner_check_typedef(void); +extern void scanner_ignore_typedef(void); +extern void scanner_clear_start(void); +extern void start_inline(char *, int); +extern void format_string(char *); +extern void swig_pragma(char *, char *); + +#include "internal.h" + +#ifdef NEED_ALLOC +void *alloca(unsigned n) { + return((void *) malloc(n)); +} +#else +// This redefinition is apparently needed on a number of machines, +// particularly HPUX +#undef alloca +#define alloca malloc +#endif + +// Initialization flags. These indicate whether or not certain +// features have been initialized. These were added to allow +// interface files without the block (required in previous +// versions). + +static int module_init = 0; /* Indicates whether the %module name was given */ +static int title_init = 0; /* Indicates whether %title directive has been given */ +static int doc_init = 0; + +static int lang_init = 0; /* Indicates if the language has been initialized */ + +static int i; + int Error = 0; +static char temp_name[128]; +static DataType *temp_typeptr, temp_type; +static char yy_rename[256]; +static int Rename_true = 0; +static DataType *Active_type = 0; // Used to support variable lists +static int Active_extern = 0; // Whether or not list is external +static int Active_static = 0; +static DataType *Active_typedef = 0; // Used for typedef lists +static int InArray = 0; // Used when an array declaration is found +static int in_then = 0; +static int in_else = 0; +static int allow = 1; // Used during conditional compilation +static int doc_scope = 0; // Documentation scoping +static String ArrayString; // Array type attached to parameter names +static String ArrayBackup; // Array backup string +static char *DefArg = 0; // Default argument hack +static char *ConstChar = 0; // Used to store raw character constants +static ParmList *tm_parm = 0; // Parameter list used to hold typemap parameters +static Hash name_hash; // Hash table containing renamings + char *objc_construct = "new"; // Objective-C constructor + char *objc_destruct = "free"; // Objective-C destructor + +/* Some macros for building constants */ + +#define E_BINARY(TARGET, SRC1, SRC2, OP) \ + TARGET = new char[strlen(SRC1) + strlen(SRC2) +strlen(OP)+1];\ + sprintf(TARGET,"%s%s%s",SRC1,OP,SRC2); + +/* C++ modes */ + +#define CPLUS_PUBLIC 1 +#define CPLUS_PRIVATE 2 +#define CPLUS_PROTECTED 3 + +int cplus_mode; + +// Declarations of some functions for handling C++ + +extern void cplus_open_class(char *name, char *rname, char *ctype); +extern void cplus_member_func(char *, char *, DataType *, ParmList *, int); +extern void cplus_constructor(char *, char *, ParmList *); +extern void cplus_destructor(char *, char *); +extern void cplus_variable(char *, char *, DataType *); +extern void cplus_static_func(char *, char *, DataType *, ParmList *); +extern void cplus_declare_const(char *, char *, DataType *, char *); +extern void cplus_class_close(char *); +extern void cplus_inherit(int, char **); +extern void cplus_cleanup(void); +extern void cplus_static_var(char *, char *, DataType *); +extern void cplus_register_type(char *); +extern void cplus_register_scope(Hash *); +extern void cplus_inherit_scope(int, char **); +extern void cplus_add_pragma(char *, char *, char *); +extern DocEntry *cplus_set_class(char *); +extern void cplus_unset_class(); +extern void cplus_abort(); + +// ---------------------------------------------------------------------- +// static init_language() +// +// Initialize the target language. +// Does nothing if this function has already been called. +// ---------------------------------------------------------------------- + +static void init_language() { + if (!lang_init) { + lang->initialize(); + + // Initialize the documentation system + + if (!doctitle) { + doctitle = new DocTitle(title,0); + } + if (!doc_init) + doctitle->usage = title; + + doc_stack[0] = doctitle; + doc_stack_top = 0; + + int oldignore = IgnoreDoc; + IgnoreDoc = 1; + if (ConfigFile) { + include_file(ConfigFile); + } + IgnoreDoc = oldignore; + } + lang_init = 1; + title_init = 1; +} + +// ---------------------------------------------------------------------- +// int promote(int t1, int t2) +// +// Promote types (for constant expressions) +// ---------------------------------------------------------------------- + +int promote(int t1, int t2) { + + if ((t1 == T_ERROR) || (t2 == T_ERROR)) return T_ERROR; + if ((t1 == T_DOUBLE) || (t2 == T_DOUBLE)) return T_DOUBLE; + if ((t1 == T_FLOAT) || (t2 == T_FLOAT)) return T_FLOAT; + if ((t1 == T_ULONG) || (t2 == T_ULONG)) return T_ULONG; + if ((t1 == T_LONG) || (t2 == T_LONG)) return T_LONG; + if ((t1 == T_UINT) || (t2 == T_UINT)) return T_UINT; + if ((t1 == T_INT) || (t2 == T_INT)) return T_INT; + if ((t1 == T_USHORT) || (t2 == T_USHORT)) return T_SHORT; + if ((t1 == T_SHORT) || (t2 == T_SHORT)) return T_SHORT; + if ((t1 == T_UCHAR) || (t2 == T_UCHAR)) return T_UCHAR; + if (t1 != t2) { + fprintf(stderr,"%s : Line %d. Type mismatch in constant expression\n", + input_file, line_number); + FatalError(); + } + return t1; +} + +/* Generate the scripting name of an object. Takes %name directive into + account among other things */ + +static char *make_name(char *name) { + // Check to see if the name is in the hash + char *nn = (char *) name_hash.lookup(name); + if (nn) return nn; // Yep, return it. + + if (Rename_true) { + Rename_true = 0; + return yy_rename; + } else { + // Now check to see if the name contains a $ + if (strchr(name,'$')) { + static String temp; + temp = ""; + temp << name; + temp.replace("$","_S_"); + return temp; + } else { + return name; + } + } +} + +/* Return the parent of a documentation entry. If wrapping externally, this is 0 */ + +static DocEntry *doc_parent() { + if (!WrapExtern) + return doc_stack[doc_stack_top]; + else + return 0; +} + +// ---------------------------------------------------------------------- +// create_function(int ext, char *name, DataType *t, ParmList *l) +// +// Creates a function and manages documentation creation. Really +// only used internally to the parser. +// ---------------------------------------------------------------------- + +void create_function(int ext, char *name, DataType *t, ParmList *l) { + if (Active_static) return; // Static declaration. Ignore + + init_language(); + if (WrapExtern) return; // External wrapper file. Ignore + + char *iname = make_name(name); + + // Check if symbol already exists + + if (add_symbol(iname, t, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Function %s multiply defined (2nd definition ignored).\n", + input_file, line_number, iname); + } else { + Stat_func++; + if (Verbose) { + fprintf(stderr,"Wrapping function : "); + emit_extern_func(name, t, l, 0, stderr); + } + + // If extern, make an extern declaration in the SWIG wrapper file + + if (ext) + emit_extern_func(name, t, l, ext, f_header); + else if (ForceExtern) { + emit_extern_func(name, t, l, 1, f_header); + } + + // If this function has been declared inline, produce a function + + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + lang->create_function(name, iname, t, l); + l->check_defined(); + t->check_defined(); + } + scanner_clear_start(); +} + +// ------------------------------------------------------------------- +// create_variable(int ext, char *name, DataType *t) +// +// Create a link to a global variable. +// ------------------------------------------------------------------- + +void create_variable(int ext, char *name, DataType *t) { + + if (WrapExtern) return; // External wrapper file. Ignore + int oldstatus = Status; + + if (Active_static) return; // If static ignore + + init_language(); + + char *iname = make_name(name); + if (add_symbol(iname, t, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Variable %s multiply defined (2nd definition ignored).\n", + input_file, line_number, iname); + } else { + Stat_var++; + if (Verbose) { + fprintf(stderr,"Wrapping variable : "); + emit_extern_var(name, t, 0, stderr); + } + + // If externed, output an external declaration + + if (ext) + emit_extern_var(name, t, ext, f_header); + else if (ForceExtern) { + emit_extern_var(name, t, 1, f_header); + } + + // If variable datatype is read-only, we'll force it to be readonly + if (t->status & STAT_READONLY) Status = Status | STAT_READONLY; + + // Now dump it out + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + lang->link_variable(name, iname, t); + t->check_defined(); + Status = oldstatus; + } + scanner_clear_start(); +} + +// ------------------------------------------------------------------ +// create_constant(char *name, DataType *type, char *value) +// +// Creates a new constant. +// ------------------------------------------------------------------- + +void create_constant(char *name, DataType *type, char *value) { + + if (Active_static) return; + if (WrapExtern) return; // External wrapper file. Ignore + init_language(); + + if (Rename_true) { + fprintf(stderr,"%s : Line %d. %%name directive ignored with #define\n", + input_file, line_number); + Rename_true = 0; + } + + if ((type->type == T_CHAR) && (!type->is_pointer)) + type->is_pointer++; + + if (!value) value = copy_string(name); + sprintf(temp_name,"const:%s", name); + if (add_symbol(temp_name, type, value)) { + fprintf(stderr,"%s : Line %d. Constant %s multiply defined. (2nd definition ignored)\n", + input_file, line_number, name); + } else { + // Update symbols value if already defined. + update_symbol(name, type, value); + + if (!WrapExtern) { // Only wrap the constant if not in %extern mode + Stat_const++; + if (Verbose) + fprintf(stderr,"Creating constant %s = %s\n", name, value); + + doc_entry = new DocDecl(name,doc_stack[doc_stack_top]); + lang->declare_const(name, name, type, value); + type->check_defined(); + } + } + scanner_clear_start(); +} + + +/* Print out array brackets */ +void print_array() { + int i; + for (i = 0; i < InArray; i++) + fprintf(stderr,"[]"); +} + +/* manipulate small stack for managing if-then-else */ + +static int then_data[100]; +static int else_data[100]; +static int allow_data[100]; +static int te_index = 0; +static int prev_allow = 1; + +void if_push() { + then_data[te_index] = in_then; + else_data[te_index] = in_else; + allow_data[te_index] = allow; + prev_allow = allow; + te_index++; + if (te_index >= 100) { + fprintf(stderr,"SWIG. Internal parser error. if-then-else stack overflow.\n"); + SWIG_exit(1); + } +} + +void if_pop() { + if (te_index > 0) { + te_index--; + in_then = then_data[te_index]; + in_else = else_data[te_index]; + allow = allow_data[te_index]; + if (te_index > 0) { + prev_allow = allow_data[te_index-1]; + } else { + prev_allow = 1; + } + } +} + +// Structures for handling code fragments built for nested classes + +struct Nested { + String code; // Associated code fragment + int line; // line number where it starts + char *name; // Name associated with this nested class + DataType *type; // Datatype associated with the name + Nested *next; // Next code fragment in list +}; + +// Some internal variables for saving nested class information + +static Nested *nested_list = 0; + +// Add a function to the nested list + +static void add_nested(Nested *n) { + Nested *n1; + if (!nested_list) nested_list = n; + else { + n1 = nested_list; + while (n1->next) n1 = n1->next; + n1->next = n; + } +} + +// Dump all of the nested class declarations to the inline processor +// However. We need to do a few name replacements and other munging +// first. This function must be called before closing a class! + +static void dump_nested(char *parent) { + Nested *n,*n1; + n = nested_list; + int oldstatus = Status; + + Status = STAT_READONLY; + while (n) { + // Token replace the name of the parent class + n->code.replace("$classname",parent); + + // Fix up the name of the datatype (for building typedefs and other stuff) + sprintf(n->type->name,"%s_%s",parent,n->name); + + // Add the appropriate declaration to the C++ processor + doc_entry = new DocDecl(n->name,doc_stack[doc_stack_top]); + cplus_variable(n->name,(char *) 0, n->type); + + // Dump the code to the scanner + if (Verbose) + fprintf(stderr,"Splitting from %s : (line %d) \n%s\n", parent,n->line, n->code.get()); + + fprintf(f_header,"\n%s\n", n->code.get()); + start_inline(n->code.get(),n->line); + + n1 = n->next; + delete n; + n = n1; + } + nested_list = 0; + Status = oldstatus; +} + +%} + +/* The type of each node in the parse tree + must be one of the elements of the union + given below. This is used to derive the + C++ declaration for "yylval" that appears + in parser.tab.h. */ + +%union { + char *id; + struct Declaration { + char *id; + int is_pointer; + int is_reference; + } decl; + struct InitList { + char **names; + int count; + } ilist; + struct DocList { + char **names; + char **values; + int count; + } dlist; + struct Define { + char *id; + int type; + } dtype; + DataType *type; + Parm *p; + TMParm *tmparm; + ParmList *pl; + int ivalue; +}; + +%token ID +%token HBLOCK WRAPPER POUND +%token STRING +%token NUM_INT NUM_FLOAT CHARCONST NUM_UNSIGNED NUM_LONG NUM_ULONG +%token TYPEDEF +%token TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_TYPEDEF +%token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE DEFINE PERIOD +%token CONST STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET +%token WEXTERN ILLEGAL +%token READONLY READWRITE NAME RENAME INCLUDE CHECKOUT ADDMETHODS PRAGMA +%token CVALUE COUT +%token ENUM ENDDEF MACRO +%token CLASS PRIVATE PUBLIC PROTECTED COLON STATIC VIRTUAL FRIEND OPERATOR THROW TEMPLATE +%token NATIVE INLINE +%token IFDEF IFNDEF ENDIF ELSE UNDEF IF DEFINED ELIF +%token RAW_MODE ALPHA_MODE TEXT DOC_DISABLE DOC_ENABLE STYLE LOCALSTYLE +%token TYPEMAP EXCEPT IMPORT ECHO NEW APPLY CLEAR DOCONLY +%token TITLE SECTION SUBSECTION SUBSUBSECTION +%token LESSTHAN GREATERTHAN +%token USERDIRECTIVE + +/* Objective C tokens */ + +%token OC_INTERFACE OC_END OC_PUBLIC OC_PRIVATE OC_PROTECTED OC_CLASS OC_IMPLEMENT OC_PROTOCOL + +%left OR +%left XOR +%left AND +%left LSHIFT RSHIFT +%left PLUS MINUS +%left STAR SLASH +%left UMINUS NOT LNOT +%left DCOLON + +%type extern array array2 parm_specifier parm_specifier_list; +%type parms ptail; +%type

    parm parm_type; +%type typemap_parm tm_list tm_tail; +%type pname cpptype base_specifier access_specifier typemap_name tm_method idstring; +%type type opt_signed opt_unsigned strict_type; +%type declaration nested_decl; +%type stars cpp_const_expr; +%type initlist base_list inherit; +%type definetype definetail def_args; +%type etype; +%type expr; +%type ename stylearg objc_inherit; +%type stylelist styletail; +%type objc_ret_type objc_arg_type; +%type objc_protolist objc_separator; +%type objc_args; + +%% + +/* The productions of the grammar with their + associated semantic actions. */ + +program : { + { + int ii; + for (ii = 0; ii < 256; ii++) { + handler_stack[ii] = 0; + } + handler_stack[0] = comment_handler; + } + doc_stack[0] = doctitle; + } command { + CommentHandler::cleanup(); + cplus_cleanup(); + doc_entry = doctitle; + if (lang_init) { + lang->close(); + } + if (te_index) { + fprintf(stderr,"%s : EOF. Missing #endif detected.\n", input_file); + FatalError(); + } + } + ; + +command : command statement { + scanner_clear_start(); + Error = 0; + } + | empty { + } + ; + +statement : INCLUDE idstring { + if (allow) { +// init_language(); + doc_entry = 0; + // comment_handler->clear(); + include_file($2); + } + } + +/* %extern directive */ + + | WEXTERN idstring { + if (allow) { + int oldextern = WrapExtern; +// init_language(); + doc_entry = 0; + // comment_handler->clear(); + WrapExtern = 1; + if (include_file($2) >= 0) { + add_symbol("SWIGEXTERN",0,0); + } else { + WrapExtern = oldextern; + } + } + } + +/* %import directive. Like %extern but calls out to a language module */ + + | IMPORT idstring { + if (allow) { + int oldextern = WrapExtern; + init_language(); + doc_entry = 0; + WrapExtern = 1; + if (include_file($2) >= 0) { + add_symbol("SWIGEXTERN",0,0); + lang->import($2); + } else { + WrapExtern = oldextern; + } + } + } + +/* %checkout directive. Like %include, but simply copies the file into the + current directory */ + + | CHECKOUT idstring { + if (allow) { + if ((checkout_file($2,$2)) == 0) { + fprintf(stderr,"%s checked out from the SWIG library.\n",$2); + } + } + } + +/* An unknown C preprocessor statement. Just throw it away */ + + | POUND { + if (allow) { + doc_entry = 0; + if (Verbose) { + fprintf(stderr,"%s : Line %d. CPP %s ignored.\n", input_file, line_number,$1); + } + } + } + +/* A variable declaration */ + + | extern type declaration array2 def_args { + if (allow) { + init_language(); + if (Active_type) delete Active_type; + Active_type = new DataType($2); + Active_extern = $1; + $2->is_pointer += $3.is_pointer; + if ($4 > 0) { + $2->is_pointer++; + $2->status = STAT_READONLY; + $2->arraystr = copy_string(ArrayString); + } + if ($3.is_reference) { + fprintf(stderr,"%s : Line %d. Error. Linkage to C++ reference not allowed.\n", input_file, line_number); + FatalError(); + } else { + if ($2->qualifier) { + if ((strcmp($2->qualifier,"const") == 0)) { + if ($5.type != T_ERROR) + create_constant($3.id, $2, $5.id); + } else + create_variable($1,$3.id,$2); + } else + create_variable($1,$3.id,$2); + } + } + delete $2; + } stail { } + +/* Global variable that smells like a function pointer */ + + | extern strict_type LPAREN STAR { + skip_decl(); + fprintf(stderr,"%s : Line %d. Function pointers not currently supported.\n", + input_file, line_number); + } + +/* A static variable declaration (Ignored) */ + + | STATIC type declaration array2 def_args { + if (Verbose) { + fprintf(stderr,"static variable %s ignored.\n",$3.id); + } + Active_static = 1; + delete $2; + } stail { + Active_static = 0; + } + +/* Global variable that smells like a function pointer */ + + | STATIC strict_type LPAREN STAR { + skip_decl(); + fprintf(stderr,"%s : Line %d. Function pointers not currently supported.\n", + input_file, line_number); + } + + +/* A function declaration */ + + | extern type declaration LPAREN parms RPAREN cpp_const { + if (allow) { + init_language(); + if (Active_type) delete Active_type; + Active_type = new DataType($2); + Active_extern = $1; + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + create_function($1, $3.id, $2, $5); + } + delete $2; + delete $5; + } stail { } + +/* A function declaration with code after it */ + + | extern type declaration LPAREN parms RPAREN func_end { + if (allow) { + init_language(); + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + create_function($1, $3.id, $2, $5); + } + delete $2; + delete $5; + }; + +/* A function declared without any return datatype */ + + | extern declaration LPAREN parms RPAREN cpp_const { + if (allow) { + init_language(); + DataType *t = new DataType(T_INT); + t->is_pointer += $2.is_pointer; + t->is_reference = $2.is_reference; + create_function($1,$2.id,t,$4); + delete t; + } + } stail { }; + +/* A static function declaration code after it */ + + | STATIC type declaration LPAREN parms RPAREN func_end { + if ((allow) && (Inline)) { + if (strlen(CCode.get())) { + init_language(); + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + create_function(0, $3.id, $2, $5); + } + } + delete $2; + delete $5; + }; + +/* A function with an explicit inline directive. Not safe to use inside a %inline block */ + + | INLINE type declaration LPAREN parms RPAREN func_end { + if (allow) { + init_language(); + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + if (Inline) { + fprintf(stderr,"%s : Line %d. Repeated %%inline directive.\n",input_file,line_number); + FatalError(); + } else { + if (strlen(CCode.get())) { + fprintf(f_header,"static "); + emit_extern_func($3.id,$2,$5,3,f_header); + fprintf(f_header,"%s\n",CCode.get()); + } + create_function(0, $3.id, $2, $5); + } + } + delete $2; + delete $5; + }; + +/* A static function declaration (ignored) */ + + | STATIC type declaration LPAREN parms RPAREN cpp_const { + if (allow) { + if (Verbose) { + fprintf(stderr,"static function %s ignored.\n", $3.id); + } + } + Active_static = 1; + delete $2; + delete $5; + } stail { + Active_static = 0; + } + +/* Enable Read-only mode */ + + | READONLY { + if (allow) + Status = Status | STAT_READONLY; + } + +/* Enable Read-write mode */ + + | READWRITE { + if (allow) + Status = Status & ~STAT_READONLY; + } + +/* New %name directive */ + | NAME LPAREN ID RPAREN { + if (allow) { + strcpy(yy_rename,$3); + Rename_true = 1; + } + } + +/* %rename directive */ + | RENAME ID ID SEMI { + if (name_hash.lookup($2)) { + name_hash.remove($2); + } + name_hash.add($2,copy_string($3)); + } + +/* %new directive */ + + | NEW { + NewObject = 1; + } statement { + NewObject = 0; + } + +/* Empty name directive. No longer allowed */ + + | NAME LPAREN RPAREN { + if (allow) { + fprintf(stderr,"%s : Lind %d. Empty %%name() is no longer supported.\n", + input_file, line_number); + FatalError(); + } + } cpp { + Rename_true = 0; + } + +/* A native wrapper function */ + + | NATIVE LPAREN ID RPAREN extern ID SEMI { + if (allow && (!WrapExtern)) { + init_language(); + if (add_symbol($3,(DataType *) 0, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Name of native function %s conflicts with previous declaration (ignored)\n", + input_file, line_number, $3); + } else { + doc_entry = new DocDecl($3,doc_stack[doc_stack_top]); + lang->add_native($3,$6); + } + } + } + | NATIVE LPAREN ID RPAREN extern type declaration LPAREN parms RPAREN SEMI { + if (allow && (!WrapExtern)) { + init_language(); + $6->is_pointer += $7.is_pointer; + if (add_symbol($3,(DataType *) 0, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Name of native function %s conflicts with previous declaration (ignored)\n", + input_file, line_number, $3); + } else { + if ($5) { + emit_extern_func($7.id, $6, $9, $5, f_header); + } + doc_entry = new DocDecl($3,doc_stack[doc_stack_top]); + lang->add_native($3,$7.id); + } + } + delete $6; + delete $9; + } + +/* %title directive */ + + | TITLE STRING styletail { + if (allow && (!WrapExtern)) { + if (!title_init) { + title_init = 1; + doc_init = 1; + if (!comment_handler) { + comment_handler = new CommentHandler(); + } + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + comment_handler->style($3.names[ii],$3.values[ii]); + } + } + // Create a new title for documentation + { + int temp = line_number; + line_number = $1; + if (!doctitle) + doctitle = new DocTitle($2,0); + else { + doctitle->name = copy_string(title); + doctitle->line_number = $1; + doctitle->end_line = $1; + } + line_number = temp; + } + doctitle->usage = $2; + doc_entry = doctitle; + doc_stack[0] = doc_entry; + doc_stack_top = 0; + handler_stack[0] = comment_handler; + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]); + } + } + + } else { + // Ignore it + } + } + } + + +/* %section directive */ + + | SECTION STRING styletail { + if (allow && (!WrapExtern) && (!IgnoreDoc)) { + // Copy old comment handler + // if (handler_stack[1]) delete handler_stack[1]; + handler_stack[1] = new CommentHandler(handler_stack[0]); + comment_handler = handler_stack[1]; + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + comment_handler->style($3.names[ii],$3.values[ii]); + } + } + { + int temp = line_number; + line_number = $1; + doc_entry = new DocSection($2,doc_stack[0]); + line_number = temp; + } + doc_stack_top = 1; + doc_stack[1] = doc_entry; + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]); + } + } + } + } + +/* %subsection directive */ + | SUBSECTION STRING styletail { + if (allow && (!WrapExtern) && (!IgnoreDoc)) { + if (doc_stack_top < 1) { + fprintf(stderr,"%s : Line %d. Can't apply %%subsection here.\n", input_file,line_number); + FatalError(); + } else { + + // Copy old comment handler + // if (handler_stack[2]) delete handler_stack[2]; + handler_stack[2] = new CommentHandler(handler_stack[1]); + comment_handler = handler_stack[2]; + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + comment_handler->style($3.names[ii],$3.values[ii]); + } + } + { + int temp = line_number; + line_number = $1; + doc_entry = new DocSection($2,doc_stack[1]); + line_number = temp; + } + doc_stack_top = 2; + doc_stack[2] = doc_entry; + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]); + } + } + } + } + } + +/* %subsubsection directive */ + | SUBSUBSECTION STRING styletail { + if (allow && (!WrapExtern) && (!IgnoreDoc)) { + if (doc_stack_top < 2) { + fprintf(stderr,"%s : Line %d. Can't apply %%subsubsection here.\n", input_file,line_number); + FatalError(); + } else { + + // Copy old comment handler + + // if (handler_stack[3]) delete handler_stack[3]; + handler_stack[3] = new CommentHandler(handler_stack[2]); + comment_handler = handler_stack[3]; + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + comment_handler->style($3.names[ii],$3.values[ii]); + } + } + { + int temp = line_number; + line_number = $1; + doc_entry = new DocSection($2,doc_stack[2]); + line_number = temp; + } + doc_stack_top = 3; + doc_stack[3] = doc_entry; + { + int ii; + for (ii = 0; ii < $3.count; ii++) { + doc_stack[doc_stack_top]->style($3.names[ii],$3.values[ii]); + } + } + } + } + } + +/* %alpha directive (obsolete) */ + | ALPHA_MODE { + if (allow && (!WrapExtern)) { + fprintf(stderr,"%%alpha directive is obsolete. Use '%%style sort' instead.\n"); + handler_stack[0]->style("sort",0); + doc_stack[0]->style("sort",0); + } + } +/* %raw directive (obsolete) */ + | RAW_MODE { + if (allow && (!WrapExtern)) { + fprintf(stderr,"%%raw directive is obsolete. Use '%%style nosort' instead.\n"); + handler_stack[0]->style("nosort",0); + doc_stack[0]->style("nosort",0); + } + } + + | doc_enable { } + +/* %text directive */ + + | TEXT HBLOCK { + if (allow && (!WrapExtern)) { + $2[strlen($2) - 1] = 0; + doc_entry = new DocText($2,doc_stack[doc_stack_top]); + doc_entry = 0; + } + } + + + | typedef_decl { } + +/* Code insertion block */ + + | HBLOCK { + if (allow && (!WrapExtern)) { + init_language(); + $1[strlen($1) - 1] = 0; +// fprintf(f_header,"#line %d \"%s\"\n", start_line, input_file); + fprintf(f_header, "%s\n", $1); + } + } + +/* Super-secret undocumented for people who really know what's going on feature */ + + | WRAPPER HBLOCK { + if (allow && (!WrapExtern)) { + init_language(); + $2[strlen($2) - 1] = 0; + fprintf(f_wrappers,"%s\n",$2); + } + } + +/* Initialization code */ + + | INIT HBLOCK { + if (allow && (!WrapExtern)) { + init_language(); + $2[strlen($2) -1] = 0; + fprintf(f_init,"%s\n", $2); + } + } + +/* Inline block */ + | INLINE HBLOCK { + if (allow && (!WrapExtern)) { + init_language(); + $2[strlen($2) - 1] = 0; + fprintf(f_header, "%s\n", $2); + start_inline($2,start_line); + } + } + +/* Echo mode */ + | ECHO HBLOCK { + if (allow && (!WrapExtern)) { + fprintf(stderr,"%s\n", $2); + } + } + + | ECHO STRING { + if (allow && (!WrapExtern)) { + fprintf(stderr,"%s\n", $2); + } + } + +/* Disable code generation */ + | DOCONLY { + DocOnly = 1; + } + +/* Init directive--to avoid errors in other modules */ + + | INIT ID initlist { + if (allow) { + if (!module_init) { + lang->set_init($2); + module_init = 1; + init_language(); + } else { + if (Verbose) + fprintf(stderr,"%s : Line %d. %%init %s ignored.\n", + input_file, line_number, $2); + } + if ($3.count > 0) { + fprintf(stderr,"%s : Line %d. Warning. Init list no longer supported.\n", + input_file,line_number); + } + } + for (i = 0; i < $3.count; i++) + if ($3.names[i]) delete [] $3.names[i]; + delete [] $3.names; + } +/* Module directive */ + + | MODULE ID initlist { + if (allow) { + if ($3.count) + lang->set_module($2,$3.names); + else + lang->set_module($2,0); + module_init = 1; + init_language(); + } + for (i = 0; i < $3.count; i++) + if ($3.names[i]) delete [] $3.names[i]; + delete [] $3.names; + } + +/* #define directive */ + + | DEFINE ID definetail { + if (allow) { + if (($3.type != T_ERROR) && ($3.type != T_SYMBOL)) { + init_language(); + temp_typeptr = new DataType($3.type); + create_constant($2, temp_typeptr, $3.id); + delete temp_typeptr; + } else if ($3.type == T_SYMBOL) { + // Add a symbol to the SWIG symbol table + if (add_symbol($2,(DataType *) 0, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Warning. Symbol %s already defined.\n", + input_file,line_number, $2); + } + } + } + } + +/* A CPP Macro. Ignore (hopefully) */ + + | DEFINE MACRO { + if (Verbose) { + fprintf(stderr,"%s : Line %d. CPP Macro ignored.\n", input_file, line_number); + } + } + +/* An undef directive */ + | UNDEF ID { + remove_symbol($2); + } + +/* Enumerations */ + + | extern ENUM ename LBRACE { scanner_clear_start(); } enumlist RBRACE SEMI { + if (allow) { + init_language(); + if ($3) { + temp_type.type = T_INT; + temp_type.is_pointer = 0; + temp_type.implicit_ptr = 0; + sprintf(temp_type.name,"int"); + temp_type.typedef_add($3,1); + } + } + } + +/* A typdef'd enum. Pretty common in C headers */ + + | TYPEDEF ENUM ename LBRACE { scanner_clear_start(); } enumlist RBRACE ID { + if (allow) { + init_language(); + temp_type.type = T_INT; + temp_type.is_pointer = 0; + temp_type.implicit_ptr = 0; + sprintf(temp_type.name,"int"); + Active_typedef = new DataType(&temp_type); + temp_type.typedef_add($8,1); + } + } typedeflist { } + +/* ----------------------------------------------------------------- + typemap support. + + These constructs are used to support type-maps. + ----------------------------------------------------------------- */ + +/* Create a new typemap */ + + | TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list LBRACE { + TMParm *p; + skip_brace(); + p = $7; + while (p) { + typemap_register($5,$3,p->p->t,p->p->name,CCode,p->args); + p = p->next; + } + delete $3; + delete $5; + } + +/* Create a new typemap in current language */ + | TYPEMAP LPAREN tm_method RPAREN tm_list LBRACE { + if (!typemap_lang) { + fprintf(stderr,"SWIG internal error. No typemap_lang specified.\n"); + fprintf(stderr,"typemap on %s : Line %d. will be ignored.\n",input_file,line_number); + FatalError(); + } else { + TMParm *p; + skip_brace(); + p = $5; + while (p) { + typemap_register($3,typemap_lang,p->p->t,p->p->name,CCode,p->args); + p = p->next; + } + } + delete $3; + } + +/* Clear a typemap */ + + | TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list SEMI { + TMParm *p; + p = $7; + while (p) { + typemap_clear($5,$3,p->p->t,p->p->name); + p = p->next; + } + delete $3; + delete $5; + } +/* Clear a typemap in current language */ + + | TYPEMAP LPAREN tm_method RPAREN tm_list SEMI { + if (!typemap_lang) { + fprintf(stderr,"SWIG internal error. No typemap_lang specified.\n"); + fprintf(stderr,"typemap on %s : Line %d. will be ignored.\n",input_file,line_number); + FatalError(); + } else { + TMParm *p; + p = $5; + while (p) { + typemap_clear($3,typemap_lang,p->p->t,p->p->name); + p = p->next; + } + } + delete $3; + } + +/* Copy a typemap */ + + | TYPEMAP LPAREN ID COMMA tm_method RPAREN tm_list EQUAL typemap_parm SEMI { + TMParm *p; + p = $7; + while (p) { + typemap_copy($5,$3,$9->p->t,$9->p->name,p->p->t,p->p->name); + p = p->next; + } + delete $3; + delete $5; + delete $9->p; + delete $9; + } + +/* Copy typemap in current language */ + + | TYPEMAP LPAREN tm_method RPAREN tm_list EQUAL typemap_parm SEMI { + if (!typemap_lang) { + fprintf(stderr,"SWIG internal error. No typemap_lang specified.\n"); + fprintf(stderr,"typemap on %s : Line %d. will be ignored.\n",input_file,line_number); + FatalError(); + } else { + TMParm *p; + p = $5; + while (p) { + typemap_copy($3,typemap_lang,$7->p->t,$7->p->name,p->p->t,p->p->name); + p = p->next; + } + } + delete $3; + delete $7->p; + delete $7; + } +/* ----------------------------------------------------------------- + apply and clear support (for typemaps) + ----------------------------------------------------------------- */ + + | APPLY typemap_parm LBRACE tm_list RBRACE { + TMParm *p; + p = $4; + while(p) { + typemap_apply($2->p->t,$2->p->name,p->p->t,p->p->name); + p = p->next; + } + delete $4; + delete $2->args; + delete $2; + } + | CLEAR tm_list SEMI { + TMParm *p; + p = $2; + while (p) { + typemap_clear_apply(p->p->t, p->p->name); + p = p->next; + } + } + + +/* ----------------------------------------------------------------- + exception support + + These constructs are used to define exceptions + ----------------------------------------------------------------- */ + +/* An exception definition */ + | EXCEPT LPAREN ID RPAREN LBRACE { + skip_brace(); + fragment_register("except",$3, CCode); + delete $3; + } + +/* A Generic Exception (no language specified */ + | EXCEPT LBRACE { + skip_brace(); + fragment_register("except",typemap_lang, CCode); + } + +/* Clear an exception */ + + | EXCEPT LPAREN ID RPAREN SEMI { + fragment_clear("except",$3); + } + +/* Generic clear */ + | EXCEPT SEMI { + fragment_clear("except",typemap_lang); + } + +/* Miscellaenous stuff */ + + | SEMI { } + | cpp { } + | objective_c { } + | error { + if (!Error) { + { + static int last_error_line = -1; + if (last_error_line != line_number) { + fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number); + FatalError(); + last_error_line = line_number; + // Try to make some kind of recovery. + skip_decl(); + } + Error = 1; + } + } + } + +/* A an extern C type declaration. Does nothing, but is ignored */ + + | EXTERN STRING LBRACE command RBRACE { } + | cond_compile { } + +/* Officially, this directive doesn't exist yet */ + + | pragma { } + +/* %style directive. This applies to all current styles */ + + | STYLE stylelist { + { + int ii,jj; + for (ii = 0; ii < $2.count; ii++) { + comment_handler->style($2.names[ii],$2.values[ii]); + for (jj = 0; jj < doc_stack_top; jj++) + doc_stack[jj]->style($2.names[ii],$2.values[ii]); + if (doctitle) + doctitle->style($2.names[ii],$2.values[ii]); + doc->style($2.names[ii],$2.values[ii]); + } + } + } + +/* %localstyle directive. This applies only to the current style */ + + | LOCALSTYLE stylelist { + { + int ii; + for (ii = 0; ii < $2.count; ii++) { + comment_handler = new CommentHandler(comment_handler); + handler_stack[doc_stack_top] = comment_handler; + comment_handler->style($2.names[ii],$2.values[ii]); + doc_stack[doc_stack_top]->style($2.names[ii],$2.values[ii]); + } + } + } + +/* User defined directive */ + | user_directive{ } + ; + + +/* Dcumentation disable/enable */ + +doc_enable : DOC_DISABLE { + if (allow) { + if (IgnoreDoc) { + /* Already in a disabled documentation */ + doc_scope++; + } else { + if (Verbose) + fprintf(stderr,"%s : Line %d. Documentation disabled.\n", input_file, line_number); + IgnoreDoc = 1; + doc_scope = 1; + } + } + } +/* %enabledoc directive */ + | DOC_ENABLE { + if (allow) { + if (IgnoreDoc) { + if (doc_scope > 1) { + doc_scope--; + } else { + if (Verbose) + fprintf(stderr,"%s : Line %d. Documentation enabled.\n", input_file, line_number); + IgnoreDoc = 0; + doc_scope = 0; + } + } + } + } + ; + +/* Note : This really needs to be re-done */ + +/* A typedef with pointers */ +typedef_decl : TYPEDEF type declaration { + if (allow) { + init_language(); + /* Add a new typedef */ + Active_typedef = new DataType($2); + $2->is_pointer += $3.is_pointer; + $2->typedef_add($3.id); + /* If this is %typedef, add it to the header */ + if ($1) + fprintf(f_header,"typedef %s %s;\n", $2->print_full(), $3.id); + cplus_register_type($3.id); + } + } typedeflist { }; + +/* A rudimentary typedef involving function pointers */ + + | TYPEDEF type LPAREN STAR pname RPAREN LPAREN parms RPAREN SEMI { + if (allow) { + init_language(); + /* Typedef'd pointer */ + if ($1) { + sprintf(temp_name,"(*%s)",$5); + fprintf(f_header,"typedef "); + emit_extern_func(temp_name, $2,$8,0,f_header); + } + strcpy($2->name,""); + $2->type = T_USER; + $2->is_pointer = 1; + $2->typedef_add($5,1); + cplus_register_type($5); + } + delete $2; + delete $5; + delete $8; + } + +/* A typedef involving function pointers again */ + + | TYPEDEF type stars LPAREN STAR pname RPAREN LPAREN parms RPAREN SEMI { + if (allow) { + init_language(); + if ($1) { + $2->is_pointer += $3; + sprintf(temp_name,"(*%s)",$6); + fprintf(f_header,"typedef "); + emit_extern_func(temp_name, $2,$9,0,f_header); + } + + /* Typedef'd pointer */ + strcpy($2->name,""); + $2->type = T_USER; + $2->is_pointer = 1; + $2->typedef_add($6,1); + cplus_register_type($6); + } + delete $2; + delete $6; + delete $9; + } + +/* A typedef involving arrays */ + + | TYPEDEF type declaration array { + if (allow) { + init_language(); + Active_typedef = new DataType($2); + // This datatype is going to be readonly + + $2->status = STAT_READONLY | STAT_REPLACETYPE; + $2->is_pointer += $3.is_pointer; + // Turn this into a "pointer" corresponding to the array + $2->is_pointer++; + $2->arraystr = copy_string(ArrayString); + $2->typedef_add($3.id); + fprintf(stderr,"%s : Line %d. Warning. Array type %s will be read-only without a typemap\n",input_file,line_number, $3.id); + cplus_register_type($3.id); + + } + } typedeflist { } + ; + +/* ------------------------------------------------------------------------ + Typedef list + + The following rules are used to manage typedef lists. Only a temporary + hack until the SWIG 2.0 parser gets online. + + Active_typedef contains the datatype of the last typedef (if applicable) + ------------------------------------------------------------------------ */ + + +typedeflist : COMMA declaration typedeflist { + if (allow) { + if (Active_typedef) { + DataType *t; + t = new DataType(Active_typedef); + t->is_pointer += $2.is_pointer; + t->typedef_add($2.id); + cplus_register_type($2.id); + delete t; + } + } + } + | COMMA declaration array { + DataType *t; + t = new DataType(Active_typedef); + t->status = STAT_READONLY | STAT_REPLACETYPE; + t->is_pointer += $2.is_pointer + 1; + t->arraystr = copy_string(ArrayString); + t->typedef_add($2.id); + cplus_register_type($2.id); + delete t; + fprintf(stderr,"%s : Line %d. Warning. Array type %s will be read-only without a typemap.\n",input_file,line_number, $2.id); + } + | empty { } + ; + +/* ---------------------------------------------------------------------------------- + Conditional Compilation + + SWIG supports the following constructs + #ifdef + #ifndef + #else + #endif + #if defined(ID) + #if ! defined(ID) + #elif + + #if, and #elif are a little weak in this implementation + ---------------------------------------------------------------------------------- */ + + +/* #ifdef directive */ +cond_compile : IFDEF ID { + /* Push old if-then-else status */ + if_push(); + /* Look a symbol up in the symbol table */ + if (lookup_symbol($2)) { + in_then = 1; + in_else = 0; + allow = 1 & prev_allow; + } else { + /* Condition is false. Skip over whatever is in this block */ + in_else = skip_cond(1); + if (in_else == -1) { + /* Unrecoverable error */ + SWIG_exit(1); + } + if (!in_else) { + if_pop(); // Pop out. Reached end of block + } else { + allow = prev_allow; + in_then = 0; + } + } + } + +/* #ifndef directive */ + + | IFNDEF ID { + if_push(); + if (lookup_symbol($2)) { + /* Condition is false. Skip over whatever is in this block */ + in_else = skip_cond(1); + if (in_else == -1) { + /* Unrecoverable error */ + SWIG_exit(1); + } + if (!in_else) { + if_pop(); // Pop out. Reached end of block + } else { + allow = prev_allow; + in_then = 0; + } + } else { + in_then = 1; + in_else = 0; + allow = 1 & prev_allow; + } + } + +/* #else directive */ + | ELSE { + if ((!in_then) || (in_else)) { + fprintf(stderr,"%s : Line %d. Misplaced else\n", input_file, line_number); + FatalError(); + } else { + in_then = 0; + in_else = 1; + if (allow) { + allow = 0; + /* Skip over rest of the conditional */ + skip_cond(0); + if_pop(); + } else { + allow = 1; + } + allow = allow & prev_allow; + } + } +/* #endif directive */ + | ENDIF { + if ((!in_then) && (!in_else)) { + fprintf(stderr,"%s : Line %d. Misplaced endif\n", input_file, line_number); + FatalError(); + } else { + if_pop(); + } + } + +/* #if */ + | IF cpp_const_expr { + /* Push old if-then-else status */ + if_push(); + if ($2) { + in_then = 1; + in_else = 0; + allow = 1 & prev_allow; + } else { + /* Condition is false. Skip over whatever is in this block */ + in_else = skip_cond(1); + if (in_else == -1) { + /* Unrecoverable error */ + SWIG_exit(1); + } + if (!in_else) { + if_pop(); // Pop out. Reached end of block + } else { + allow = prev_allow; + in_then = 0; + } + } + } + +/* #elif. We treat this identical to an #if. Abit of a hack, but what + the hell. */ + + | ELIF cpp_const_expr { + /* have to pop old if clause off */ + if_pop(); + + /* Push old if-then-else status */ + if_push(); + if ($2) { + in_then = 1; + in_else = 0; + allow = 1 & prev_allow; + } else { + /* Condition is false. Skip over whatever is in this block */ + in_else = skip_cond(1); + if (in_else == -1) { + /* Unrecoverable error */ + SWIG_exit(1); + } + if (!in_else) { + if_pop(); // Pop out. Reached end of block + } else { + allow = prev_allow; + in_then = 0; + } + } + } + ; + +/* C preprocessor expression (only used for conditional compilation */ + +cpp_const_expr : DEFINED LPAREN ID RPAREN { + + /* Look ID up in the symbol table */ + if (lookup_symbol($3)) { + $$ = 1; + } else { + $$ = 0; + } + } + | DEFINED ID { + if (lookup_symbol($2)) { + $$ = 1; + } else { + $$ = 0; + } + } + | LNOT cpp_const_expr { + if ($2) $$ = 0; + else $$ = 1; + } + ; + +pragma : PRAGMA LPAREN ID COMMA ID stylearg RPAREN { + if (allow && (!WrapExtern)) + lang->pragma($3,$5,$6); + fprintf(stderr,"%s : Line %d. Warning. '%%pragma(lang,opt=value)' syntax is obsolete.\n", + input_file,line_number); + fprintf(stderr," Use '%%pragma(lang) opt=value' instead.\n"); + } + + | PRAGMA ID stylearg { + if (allow && (!WrapExtern)) + swig_pragma($2,$3); + } + | PRAGMA LPAREN ID RPAREN ID stylearg { + if (allow && (!WrapExtern)) + lang->pragma($3,$5,$6); + } + ; + +/* Allow lists of variables and functions to be built up */ + +stail : SEMI { } + | COMMA declaration array2 def_args { + if (allow) { + init_language(); + temp_typeptr = new DataType(Active_type); + temp_typeptr->is_pointer += $2.is_pointer; + if ($3 > 0) { + temp_typeptr->is_pointer++; + temp_typeptr->status = STAT_READONLY; + temp_typeptr->arraystr = copy_string(ArrayString); + } + if ($2.is_reference) { + fprintf(stderr,"%s : Line %d. Error. Linkage to C++ reference not allowed.\n", input_file, line_number); + FatalError(); + } else { + if (temp_typeptr->qualifier) { + if ((strcmp(temp_typeptr->qualifier,"const") == 0)) { + /* Okay. This is really some sort of C++ constant here. */ + if ($4.type != T_ERROR) + create_constant($2.id, temp_typeptr, $4.id); + } else + create_variable(Active_extern,$2.id, temp_typeptr); + } else + create_variable(Active_extern, $2.id, temp_typeptr); + } + delete temp_typeptr; + } + } stail { } + | COMMA declaration LPAREN parms RPAREN cpp_const { + if (allow) { + init_language(); + temp_typeptr = new DataType(Active_type); + temp_typeptr->is_pointer += $2.is_pointer; + temp_typeptr->is_reference = $2.is_reference; + create_function(Active_extern, $2.id, temp_typeptr, $4); + delete temp_typeptr; + } + delete $4; + } stail { } + ; + +definetail : definetype ENDDEF { + $$ = $1; + } + | ENDDEF { + $$.type = T_SYMBOL; + } + | error ENDDEF { + if (Verbose) + fprintf(stderr,"%s : Line %d. Warning. Unable to parse #define (ignored)\n", input_file, line_number); + $$.type = T_ERROR; + } + + ; + +extern : EXTERN { $$ = 1; } + | empty {$$ = 0; } + | EXTERN STRING { + if (strcmp($2,"C") == 0) { + $$ = 2; + } else { + fprintf(stderr,"%s : Line %d. Unrecognized extern type \"%s\" (ignored).\n", input_file, line_number, $2); + FatalError(); + } + } + ; + +/* End of a function declaration. Allows C++ "const" directive and inline code */ + +func_end : cpp_const LBRACE { skip_brace(); } +/* | LBRACE { skip_brace(); } */ + ; + +/* ------------------------------------------------------------------------------ + Function parameter lists + + ------------------------------------------------------------------------------ */ + +parms : parm ptail { + if (($1->t->type != T_VOID) || ($1->t->is_pointer)) + $2->insert($1,0); + $$ = $2; + delete $1; + } + | empty { $$ = new ParmList;} + ; + +ptail : COMMA parm ptail { + $3->insert($2,0); + $$ = $3; + delete $2; + } + | empty { $$ = new ParmList;} + ; + +parm : parm_type { + $$ = $1; + if (typemap_check("ignore",typemap_lang,$$->t,$$->name)) + $$->ignore = 1; + } + | parm_specifier_list parm_type { + $$ = $2; + $$->call_type = $$->call_type | $1; + if (InArray && ($$->call_type & CALL_VALUE)) { + fprintf(stderr,"%s : Line %d. Error. Can't use %%val with an array.\n", input_file, line_number); + FatalError(); + } + if (!$$->t->is_pointer) { + fprintf(stderr,"%s : Line %d. Error. Can't use %%val or %%out with a non-pointer argument.\n", input_file, line_number); + FatalError(); + } else { + $$->t->is_pointer--; + } + } + +parm_type : type pname { + if (InArray) { + $1->is_pointer++; + if (Verbose) { + fprintf(stderr,"%s : Line %d. Warning. Array %s", input_file, line_number, $1->print_type()); + print_array(); + fprintf(stderr," has been converted to %s.\n", $1->print_type()); + } + // Add array string to the type + $1->arraystr = copy_string(ArrayString.get()); + } + $$ = new Parm($1,$2); + $$->call_type = 0; + $$->defvalue = DefArg; + if (($1->type == T_USER) && !($1->is_pointer)) { + if (Verbose) + fprintf(stderr,"%s : Line %d. Warning : Parameter of type '%s'\nhas been remapped to '%s *' and will be called using *((%s *) ptr).\n", + input_file, line_number, $1->name, $1->name, $1->name); + + $$->call_type = CALL_REFERENCE; + $$->t->is_pointer++; + } + delete $1; + delete $2; + } + + | type stars pname { + $$ = new Parm($1,$3); + $$->t->is_pointer += $2; + $$->call_type = 0; + $$->defvalue = DefArg; + if (InArray) { + $$->t->is_pointer++; + if (Verbose) { + fprintf(stderr,"%s : Line %d. Warning. Array %s", input_file, line_number, $$->t->print_type()); + print_array(); + fprintf(stderr," has been converted to %s.\n", $$->t->print_type()); + } + // Add array string to the type + $$->t->arraystr = copy_string(ArrayString.get()); + } + delete $1; + delete $3; + } + + | type AND pname { + $$ = new Parm($1,$3); + $$->t->is_reference = 1; + $$->call_type = 0; + $$->t->is_pointer++; + $$->defvalue = DefArg; + if (!CPlusPlus) { + fprintf(stderr,"%s : Line %d. Warning. Use of C++ Reference detected. Use the -c++ option.\n", input_file, line_number); + } + delete $1; + delete $3; + } + | type LPAREN stars pname RPAREN LPAREN parms RPAREN { + fprintf(stderr,"%s : Line %d. Error. Function pointer not allowed (remap with typedef).\n", input_file, line_number); + FatalError(); + $$ = new Parm($1,$4); + $$->t->type = T_ERROR; + $$->name = copy_string($4); + strcpy($$->t->name,""); + delete $1; + delete $4; + delete $7; + } + | PERIOD PERIOD PERIOD { + fprintf(stderr,"%s : Line %d. Variable length arguments not supported (ignored).\n", input_file, line_number); + $$ = new Parm(new DataType(T_INT),"varargs"); + $$->t->type = T_ERROR; + $$->name = copy_string("varargs"); + strcpy($$->t->name,""); + FatalError(); + } + ; + +pname : ID def_args { + $$ = $1; + InArray = 0; + if ($2.type == T_CHAR) + DefArg = copy_string(ConstChar); + else + DefArg = copy_string($2.id); + if ($2.id) delete $2.id; + } + | ID array { + $$ = $1; + InArray = $2; + DefArg = 0; + } + | array { + $$ = new char[1]; + $$[0] = 0; + InArray = $1; + DefArg = 0; + } + | empty { $$ = new char[1]; + $$[0] = 0; + InArray = 0; + DefArg = 0; + } + ; + +def_args : EQUAL definetype { $$ = $2; } + | EQUAL AND ID { + $$.id = new char[strlen($3)+2]; + $$.id[0] = '&'; + strcpy(&$$.id[1], $3); + $$.type = T_USER; + } + | EQUAL LBRACE { + skip_brace(); + $$.id = 0; $$.type = T_INT; + } + | COLON NUM_INT { + } + | empty {$$.id = 0; $$.type = T_INT;} + ; + +parm_specifier : CVALUE { $$ = CALL_VALUE; } + | COUT { $$ = CALL_OUTPUT; } + ; + +parm_specifier_list : parm_specifier_list parm_specifier { + $$ = $1 | $2; + } + | parm_specifier { + $$ = $1; + } + ; + +/* Declaration must be an identifier, possibly preceded by a * for pointer types */ + +declaration : ID { $$.id = $1; + $$.is_pointer = 0; + $$.is_reference = 0; + } + | stars ID { + $$.id = $2; + $$.is_pointer = $1; + $$.is_reference = 0; + } + | AND ID { + $$.id = $2; + $$.is_pointer = 1; + $$.is_reference = 1; + if (!CPlusPlus) { + fprintf(stderr,"%s : Line %d. Warning. Use of C++ Reference detected. Use the -c++ option.\n", input_file, line_number); + } + } + ; + +stars : STAR empty { $$ = 1; } + | STAR stars { $$ = $2 + 1;} + ; + + +array : LBRACKET RBRACKET array2 { + $$ = $3 + 1; + "[]" >> ArrayString; + } + | LBRACKET expr RBRACKET array2 { + $$ = $4 + 1; + "]" >> ArrayString; + $2.id >> ArrayString; + "[" >> ArrayString; + } + ; +array2 : array { + $$ = $1; + } + | empty { $$ = 0; + ArrayString = ""; + } + ; + +/* Data type must be a built in type or an identifier for user-defined types + This type can be preceded by a modifier. */ + +type : TYPE_INT { + $$ = $1; + } + | TYPE_SHORT opt_int { + $$ = $1; + } + | TYPE_LONG opt_int { + $$ = $1; + } + | TYPE_CHAR { + $$ = $1; + } + | TYPE_BOOL { + $$ = $1; + } + | TYPE_FLOAT { + $$ = $1; + } + | TYPE_DOUBLE { + $$ = $1; + } + | TYPE_VOID { + $$ = $1; + } + | TYPE_SIGNED opt_signed { + if ($2) $$ = $2; + else $$ = $1; + } + | TYPE_UNSIGNED opt_unsigned { + if ($2) $$ = $2; + else $$ = $1; + } + | TYPE_TYPEDEF objc_protolist { + $$ = $1; + if (strlen($2) > 0) { + if ((strlen($2) + strlen($$->name)) >= MAX_NAME) { + fprintf(stderr,"%s : Line %d. Fatal error. Type-name is too long!\n", + input_file, line_number); + } else { + strcat($$->name,$2); + } + } + } + | ID objc_protolist { + $$ = new DataType; + strcpy($$->name,$1); + $$->type = T_USER; + /* Do a typedef lookup */ + $$->typedef_resolve(); + if (strlen($2) > 0) { + if ((strlen($2) + strlen($$->name)) >= MAX_NAME) { + fprintf(stderr,"%s : Line %d. Fatal error. Type-name is too long!\n", + input_file, line_number); + } else { + strcat($$->name,$2); + } + } + } + | CONST type { + $$ = $2; + $$->qualifier = new char[6]; + strcpy($$->qualifier,"const"); + } + | cpptype ID { + $$ = new DataType; + sprintf($$->name,"%s %s",$1, $2); + $$->type = T_USER; + } + | ID DCOLON ID { + $$ = new DataType; + sprintf($$->name,"%s::%s",$1,$3); + $$->type = T_USER; + $$->typedef_resolve(); + } +/* This declaration causes a shift-reduce conflict. Unresolved for now */ + + + | DCOLON ID { + $$ = new DataType; + sprintf($$->name,"%s", $2); + $$->type = T_USER; + $$->typedef_resolve(1); + } + | ENUM ID { + $$ = new DataType; + sprintf($$->name,"enum %s", $2); + $$->type = T_INT; + $$->typedef_resolve(1); + } + ; + +/* type specification without ID symbol. Used in some cases to prevent shift-reduce conflicts */ + +strict_type : TYPE_INT { + $$ = $1; + } + | TYPE_SHORT opt_int { + $$ = $1; + } + | TYPE_LONG opt_int { + $$ = $1; + } + | TYPE_CHAR { + $$ = $1; + } + | TYPE_BOOL { + $$ = $1; + } + | TYPE_FLOAT { + $$ = $1; + } + | TYPE_DOUBLE { + $$ = $1; + } + | TYPE_VOID { + $$ = $1; + } + | TYPE_SIGNED opt_signed { + if ($2) $$ = $2; + else $$ = $1; + } + | TYPE_UNSIGNED opt_unsigned { + if ($2) $$ = $2; + else $$ = $1; + } + | TYPE_TYPEDEF objc_protolist { + $$ = $1; + strcat($$->name,$2); + } + | CONST type { + $$ = $2; + $$->qualifier = new char[6]; + strcpy($$->qualifier,"const"); + } + | cpptype ID { + $$ = new DataType; + sprintf($$->name,"%s %s",$1, $2); + $$->type = T_USER; + } + ; + +/* Optional signed types */ + +opt_signed : empty { + $$ = (DataType *) 0; + } + | TYPE_INT { + $$ = $1; + $$->type = T_INT; + sprintf(temp_name,"signed %s",$1->name); + strcpy($$->name,temp_name); + } + | TYPE_SHORT opt_int { + $$ = $1; + $$->type = T_SHORT; + sprintf(temp_name,"signed %s",$1->name); + strcpy($$->name,temp_name); + } + | TYPE_LONG opt_int { + $$ = $1; + $$->type = T_LONG; + sprintf(temp_name,"signed %s",$1->name); + strcpy($$->name,temp_name); + } + | TYPE_CHAR { + $$ = $1; + $$->type = T_SCHAR; + sprintf(temp_name,"signed %s",$1->name); + strcpy($$->name,temp_name); + } + ; + +/* Optional unsigned types */ + +opt_unsigned : empty { + $$ = (DataType *) 0; + } + | TYPE_INT { + $$ = $1; + $$->type = T_UINT; + sprintf(temp_name,"unsigned %s",$1->name); + strcpy($$->name,temp_name); + } + | TYPE_SHORT opt_int { + $$ = $1; + $$->type = T_USHORT; + sprintf(temp_name,"unsigned %s",$1->name); + strcpy($$->name,temp_name); + } + | TYPE_LONG opt_int { + $$ = $1; + $$->type = T_ULONG; + sprintf(temp_name,"unsigned %s",$1->name); + strcpy($$->name,temp_name); + } + | TYPE_CHAR { + $$ = $1; + $$->type = T_UCHAR; + sprintf(temp_name,"unsigned %s",$1->name); + strcpy($$->name,temp_name); + } + ; + +opt_int : TYPE_INT { } + | empty { } + ; + +definetype : { scanner_check_typedef(); } expr { + $$ = $2; + scanner_ignore_typedef(); + if (ConstChar) delete ConstChar; + ConstChar = 0; + } + | STRING { + $$.id = $1; + $$.type = T_CHAR; + if (ConstChar) delete ConstChar; + ConstChar = new char[strlen($1)+3]; + sprintf(ConstChar,"\"%s\"",$1); + } + | CHARCONST { + $$.id = $1; + $$.type = T_CHAR; + if (ConstChar) delete ConstChar; + ConstChar = new char[strlen($1)+3]; + sprintf(ConstChar,"'%s'",$1); + } + ; + + +/* Initialization function links */ + +initlist : initlist COMMA ID { + $$ = $1; + $$.names[$$.count] = copy_string($3); + $$.count++; + $$.names[$$.count] = (char *) 0; + } + | empty { + $$.names = new char *[NI_NAMES]; + $$.count = 0; + for (i = 0; i < NI_NAMES; i++) + $$.names[i] = (char *) 0; + } + ; + +/* Some stuff for handling enums */ + +ename : ID { $$ = $1; } + | empty { $$ = (char *) 0;} + ; + +/* SWIG enum list. +*/ + +enumlist : enumlist COMMA edecl {} + | edecl {} + ; + + +edecl : ID { + temp_typeptr = new DataType(T_INT); + create_constant($1, temp_typeptr, $1); + delete temp_typeptr; + } + | ID EQUAL { scanner_check_typedef();} etype { + temp_typeptr = new DataType($4.type); +// Use enum name instead of value +// OLD create_constant($1, temp_typeptr, $4.id); + create_constant($1, temp_typeptr, $1); + delete temp_typeptr; + } + | cond_compile edecl { } + | empty { } + ; + +etype : expr { + $$ = $1; + if (($$.type != T_INT) && ($$.type != T_UINT) && + ($$.type != T_LONG) && ($$.type != T_ULONG) && + ($$.type != T_SHORT) && ($$.type != T_USHORT) && + ($$.type != T_SCHAR) && ($$.type != T_UCHAR)) { + fprintf(stderr,"%s : Lind %d. Type error. Expecting an int\n", + input_file, line_number); + FatalError(); + } + + } + | CHARCONST { + $$.id = $1; + $$.type = T_CHAR; + } + ; + +/* Arithmetic expressions. Used for constants and other cool stuff. + Really, we're not doing anything except string concatenation, but + this does allow us to parse many constant declarations. + */ + +expr : NUM_INT { + $$.id = $1; + $$.type = T_INT; + } + | NUM_FLOAT { + $$.id = $1; + $$.type = T_DOUBLE; + } + | NUM_UNSIGNED { + $$.id = $1; + $$.type = T_UINT; + } + | NUM_LONG { + $$.id = $1; + $$.type = T_LONG; + } + | NUM_ULONG { + $$.id = $1; + $$.type = T_ULONG; + } + | SIZEOF LPAREN type RPAREN { + $$.id = new char[strlen($3->name)+9]; + sprintf($$.id,"sizeof(%s)", $3->name); + $$.type = T_INT; + } + | LPAREN strict_type RPAREN expr %prec UMINUS { + $$.id = new char[strlen($4.id)+strlen($2->name)+3]; + sprintf($$.id,"(%s)%s",$2->name,$4.id); + $$.type = $2->type; + } + | ID { + $$.id = lookup_symvalue($1); + if ($$.id == (char *) 0) + $$.id = $1; + else { + $$.id = new char[strlen($$.id)+3]; + sprintf($$.id,"(%s)",lookup_symvalue($1)); + } + temp_typeptr = lookup_symtype($1); + if (temp_typeptr) $$.type = temp_typeptr->type; + else $$.type = T_INT; + } + | ID DCOLON ID { + $$.id = new char[strlen($1)+strlen($3)+3]; + sprintf($$.id,"%s::%s",$1,$3); + $$.type = T_INT; + delete $1; + delete $3; + } + | expr PLUS expr { + E_BINARY($$.id,$1.id,$3.id,"+"); + $$.type = promote($1.type,$3.type); + delete $1.id; + delete $3.id; + } + | expr MINUS expr { + E_BINARY($$.id,$1.id,$3.id,"-"); + $$.type = promote($1.type,$3.type); + delete $1.id; + delete $3.id; + } + | expr STAR expr { + E_BINARY($$.id,$1.id,$3.id,"*"); + $$.type = promote($1.type,$3.type); + delete $1.id; + delete $3.id; + + } + | expr SLASH expr { + E_BINARY($$.id,$1.id,$3.id,"/"); + $$.type = promote($1.type,$3.type); + delete $1.id; + delete $3.id; + + } + | expr AND expr { + E_BINARY($$.id,$1.id,$3.id,"&"); + $$.type = promote($1.type,$3.type); + if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) { + fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number); + FatalError(); + } + delete $1.id; + delete $3.id; + + } + | expr OR expr { + E_BINARY($$.id,$1.id,$3.id,"|"); + $$.type = promote($1.type,$3.type); + if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) { + fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number); + FatalError(); + } + $$.type = T_INT; + delete $1.id; + delete $3.id; + + } + | expr XOR expr { + E_BINARY($$.id,$1.id,$3.id,"^"); + $$.type = promote($1.type,$3.type); + if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) { + fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number); + FatalError(); + } + $$.type = T_INT; + delete $1.id; + delete $3.id; + + } + | expr LSHIFT expr { + E_BINARY($$.id,$1.id,$3.id,"<<"); + $$.type = promote($1.type,$3.type); + if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) { + fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number); + FatalError(); + } + $$.type = T_INT; + delete $1.id; + delete $3.id; + + } + | expr RSHIFT expr { + E_BINARY($$.id,$1.id,$3.id,">>"); + $$.type = promote($1.type,$3.type); + if (($1.type == T_DOUBLE) || ($3.type == T_DOUBLE)) { + fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number); + FatalError(); + } + $$.type = T_INT; + delete $1.id; + delete $3.id; + + } + | MINUS expr %prec UMINUS { + $$.id = new char[strlen($2.id)+2]; + sprintf($$.id,"-%s",$2.id); + $$.type = $2.type; + delete $2.id; + + } + | NOT expr { + $$.id = new char[strlen($2.id)+2]; + sprintf($$.id,"~%s",$2.id); + if ($2.type == T_DOUBLE) { + fprintf(stderr,"%s : Line %d. Type error in constant expression (expecting integers).\n", input_file, line_number); + FatalError(); + } + $$.type = $2.type; + delete $2.id; + } + | LPAREN expr RPAREN { + $$.id = new char[strlen($2.id)+3]; + sprintf($$.id,"(%s)", $2.id); + $$.type = $2.type; + delete $2.id; + } + ; +/****************************************************************/ +/* C++ Support */ +/****************************************************************/ + +cpp : cpp_class { } + | cpp_other {} + ; + +cpp_class : + +/* A class/struct/union definition */ + extern cpptype ID inherit LBRACE { + char *iname; + if (allow) { + init_language(); + DataType::new_scope(); + + sprintf(temp_name,"CPP_CLASS:%s\n",$3); + if (add_symbol(temp_name, (DataType *) 0, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Error. %s %s is multiply defined.\n", input_file, line_number, $2, $3); + FatalError(); + } + if ((!CPlusPlus) && (strcmp($2,"class") == 0)) + fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number); + + iname = make_name($3); + doc_entry = new DocClass(iname, doc_parent()); + if (iname == $3) + cplus_open_class($3, 0, $2); + else + cplus_open_class($3, iname, $2); + if (strcmp($2,"class") == 0) + cplus_mode = CPLUS_PRIVATE; + else + cplus_mode = CPLUS_PUBLIC; + doc_stack_top++; + doc_stack[doc_stack_top] = doc_entry; + scanner_clear_start(); + nested_list = 0; + // Merge in scope from base classes + cplus_inherit_scope($4.count,$4.names); + } + } cpp_members RBRACE { + if (allow) { + if ($4.names) { + if (strcmp($2,"union") != 0) + cplus_inherit($4.count, $4.names); + else { + fprintf(stderr,"%s : Line %d. Inheritance not allowed for unions.\n",input_file, line_number); + FatalError(); + } + } + // Clean up the inheritance list + if ($4.names) { + int j; + for (j = 0; j < $4.count; j++) { + if ($4.names[j]) delete [] $4.names[j]; + } + delete [] $4.names; + } + + // Dumped nested declarations (if applicable) + dump_nested($3); + + // Save and collapse current scope + cplus_register_scope(DataType::collapse_scope($3)); + + // Restore the original doc entry for this class + doc_entry = doc_stack[doc_stack_top]; + cplus_class_close((char *) 0); + doc_entry = 0; + // Bump the documentation stack back down + doc_stack_top--; + cplus_mode = CPLUS_PUBLIC; + } + } + +/* Class with a typedef */ + + | TYPEDEF cpptype ID inherit LBRACE { + if (allow) { + char *iname; + init_language(); + DataType::new_scope(); + + sprintf(temp_name,"CPP_CLASS:%s\n",$3); + if (add_symbol(temp_name, (DataType *) 0, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Error. %s %s is multiply defined.\n", input_file, line_number, $2, $3); + FatalError(); + } + if ((!CPlusPlus) && (strcmp($2,"class") == 0)) + fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number); + + iname = make_name($3); + doc_entry = new DocClass(iname, doc_parent()); + if ($3 == iname) + cplus_open_class($3, 0, $2); + else + cplus_open_class($3, iname, $2); + if (strcmp($2,"class") == 0) + cplus_mode = CPLUS_PRIVATE; + else + cplus_mode = CPLUS_PUBLIC; + // Create a documentation entry for the class + doc_stack_top++; + doc_stack[doc_stack_top] = doc_entry; + scanner_clear_start(); + nested_list = 0; + + // Merge in scope from base classes + cplus_inherit_scope($4.count,$4.names); + + } + } cpp_members RBRACE declaration { + if (allow) { + if ($4.names) { + if (strcmp($2,"union") != 0) + cplus_inherit($4.count, $4.names); + else { + fprintf(stderr,"%s : Line %d. Inheritance not allowed for unions.\n",input_file, line_number); + FatalError(); + } + } + // Create a datatype for correctly processing the typedef + Active_typedef = new DataType(); + Active_typedef->type = T_USER; + sprintf(Active_typedef->name,"%s %s", $2,$3); + Active_typedef->is_pointer = 0; + Active_typedef->implicit_ptr = 0; + + // Clean up the inheritance list + if ($4.names) { + int j; + for (j = 0; j < $4.count; j++) { + if ($4.names[j]) delete [] $4.names[j]; + } + delete [] $4.names; + } + + if ($9.is_pointer > 0) { + fprintf(stderr,"%s : Line %d. typedef struct { } *id not supported properly. Winging it...\n", input_file, line_number); + + } + // Create dump nested class code + if ($9.is_pointer > 0) { + dump_nested($3); + } else { + dump_nested($9.id); + } + + // Collapse any datatypes created in the the class + + cplus_register_scope(DataType::collapse_scope($3)); + + doc_entry = doc_stack[doc_stack_top]; + if ($9.is_pointer > 0) { + cplus_class_close($3); + } else { + cplus_class_close($9.id); + } + doc_stack_top--; + doc_entry = 0; + + // Create a typedef in global scope + + if ($9.is_pointer == 0) + Active_typedef->typedef_add($9.id); + else { + DataType *t = new DataType(Active_typedef); + t->is_pointer += $9.is_pointer; + t->typedef_add($9.id); + cplus_register_type($9.id); + delete t; + } + cplus_mode = CPLUS_PUBLIC; + } + } typedeflist { }; + +/* An unnamed struct with a typedef */ + + | TYPEDEF cpptype LBRACE { + char *iname; + if (allow) { + init_language(); + DataType::new_scope(); + if ((!CPlusPlus) && (strcmp($2,"class") == 0)) + fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number); + + iname = make_name(""); + doc_entry = new DocClass(iname,doc_parent()); + if (strlen(iname)) + cplus_open_class("", iname, $2); + else + cplus_open_class("",0,$2); + if (strcmp($2,"class") == 0) + cplus_mode = CPLUS_PRIVATE; + else + cplus_mode = CPLUS_PUBLIC; + doc_stack_top++; + doc_stack[doc_stack_top] = doc_entry; + scanner_clear_start(); + nested_list = 0; + } + } cpp_members RBRACE declaration { + if (allow) { + if ($7.is_pointer > 0) { + fprintf(stderr,"%s : Line %d. typedef %s {} *%s not supported correctly. Will be ignored.\n", input_file, line_number, $2, $7.id); + cplus_abort(); + } else { + sprintf(temp_name,"CPP_CLASS:%s\n",$7.id); + if (add_symbol(temp_name, (DataType *) 0, (char *) 0)) { + fprintf(stderr,"%s : Line %d. Error. %s %s is multiply defined.\n", input_file, line_number, $2, $7.id); + FatalError(); + } + } + // Create a datatype for correctly processing the typedef + Active_typedef = new DataType(); + Active_typedef->type = T_USER; + sprintf(Active_typedef->name,"%s",$7.id); + Active_typedef->is_pointer = 0; + Active_typedef->implicit_ptr = 0; + + // Dump nested classes + if ($7.is_pointer == 0) + dump_nested($7.id); + + // Go back to previous scope + + cplus_register_scope(DataType::collapse_scope((char *) 0)); + + doc_entry = doc_stack[doc_stack_top]; + // Change name of doc_entry + doc_entry->name = copy_string($7.id); + if ($7.is_pointer == 0) + cplus_class_close($7.id); + doc_entry = 0; + doc_stack_top--; + cplus_mode = CPLUS_PUBLIC; + } + } typedeflist { } + ; + +cpp_other :/* A dummy class name */ + + extern cpptype ID SEMI { + char *iname; + if (allow) { + init_language(); + iname = make_name($3); + lang->cpp_class_decl($3,iname,$2); + } + } + +/* A static C++ member function (declared out of scope) */ + + | extern type declaration DCOLON ID LPAREN parms RPAREN SEMI { + if (allow) { + init_language(); + if (!CPlusPlus) + fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number); + + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + // Fix up the function name + sprintf(temp_name,"%s::%s",$3.id,$5); + if (!Rename_true) { + Rename_true = 1; + sprintf(yy_rename,"%s_%s",$3.id,$5); + } + create_function($1, temp_name, $2, $7); + } + delete $2; + delete $7; + } + +/* A static C++ member data */ + | extern type declaration DCOLON ID SEMI { + if (allow) { + init_language(); + if (!CPlusPlus) + fprintf(stderr,"%s : Line %d. *** WARNING ***. C++ mode is disabled (enable using -c++)\n", input_file, line_number); + + $2->is_pointer += $3.is_pointer; + // Fix up the function name + sprintf(temp_name,"%s::%s",$3.id,$5); + if (!Rename_true) { + Rename_true = 1; + sprintf(yy_rename,"%s_%s",$3.id,$5); + } + create_variable($1,temp_name, $2); + } + delete $2; + } + +/* Operator overloading catch */ + + | extern type declaration DCOLON OPERATOR { + fprintf(stderr,"%s : Line %d. Operator overloading not supported (ignored).\n", input_file, line_number); + skip_decl(); + delete $2; + } + + +/* Template catch */ + | TEMPLATE { + fprintf(stderr,"%s : Line %d. Templates not currently supported (ignored).\n", + input_file, line_number); + skip_decl(); + } + +/* %addmethods directive used outside of a class definition */ + + | ADDMETHODS ID LBRACE { + cplus_mode = CPLUS_PUBLIC; + doc_entry = cplus_set_class($2); + if (!doc_entry) { + doc_entry = new DocClass($2,doc_parent()); + }; + doc_stack_top++; + doc_stack[doc_stack_top] = doc_entry; + scanner_clear_start(); + AddMethods = 1; + } added_members RBRACE { + cplus_unset_class(); + doc_entry = 0; + doc_stack_top--; + AddMethods = 0; + } + ; + +added_members : cpp_member cpp_members { } + | objc_method objc_methods { } + | empty { } + ; + +cpp_members : cpp_member cpp_members {} + | ADDMETHODS LBRACE { + AddMethods = 1; + } cpp_members RBRACE { + AddMethods = 0; + } cpp_members { } + | error { + skip_decl(); + { + static int last_error_line = -1; + if (last_error_line != line_number) { + fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number); + FatalError(); + last_error_line = line_number; + } + } + } cpp_members { } + | empty { } + ; + +cpp_member : type declaration LPAREN parms RPAREN cpp_end { + char *iname; + if (allow) { + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + Stat_func++; + $1->is_pointer += $2.is_pointer; + $1->is_reference = $2.is_reference; + if (Verbose) { + fprintf(stderr,"Wrapping member function : %s\n",$2.id); + } + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_member_func($2.id, iname, $1,$4,0); + } + scanner_clear_start(); + } + delete $1; + delete $4; + } + +/* Virtual member function */ + + | VIRTUAL type declaration LPAREN parms RPAREN cpp_vend { + char *iname; + if (allow) { + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + Stat_func++; + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + if (Verbose) { + fprintf(stderr,"Wrapping virtual member function : %s\n",$3.id); + } + iname = make_name($3.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $3.id) iname = 0; + cplus_member_func($3.id,iname,$2,$5,1); + } + scanner_clear_start(); + } + delete $2; + delete $5; + } + +/* Possibly a constructor */ + | ID LPAREN parms RPAREN ctor_end { + char *iname; + if (allow) { + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + Stat_func++; + if (Verbose) { + fprintf(stderr,"Wrapping C++ constructor %s\n", $1); + } + iname = make_name($1); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $1) iname = 0; + cplus_constructor($1,iname, $3); + } + scanner_clear_start(); + } + delete $3; + } + +/* A destructor (hopefully) */ + + | NOT ID LPAREN parms RPAREN cpp_end { + char *iname; + if (allow) { + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + Stat_func++; + if (Verbose) { + fprintf(stderr,"Wrapping C++ destructor %s\n", $2); + } + iname = make_name($2); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2) iname = 0; + cplus_destructor($2,iname); + } + } + scanner_clear_start(); + } + +/* A virtual destructor */ + + | VIRTUAL NOT ID LPAREN RPAREN cpp_end { + char *iname; + if (allow) { + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + Stat_func++; + if (Verbose) { + fprintf(stderr,"Wrapping C++ destructor %s\n", $3); + } + iname = make_name($3); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $3) iname = 0; + cplus_destructor($3,iname); + } + } + scanner_clear_start(); + } + +/* Member data */ + + | type declaration def_args { + if (allow) { + char *iname; + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + if (Active_type) delete Active_type; + Active_type = new DataType($1); + $1->is_pointer += $2.is_pointer; + $1->is_reference = $2.is_reference; + if ($1->qualifier) { + if ((strcmp($1->qualifier,"const") == 0) && ($1->is_pointer == 0)) { + // Okay. This is really some sort of C++ constant here. + if ($3.type != T_ERROR) { + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_declare_const($2.id,iname, $1, $3.id); + } + } else { + int oldstatus = Status; + char *tm; + if ($1->status & STAT_READONLY) { + if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"",""))) + Status = Status | STAT_READONLY; + } + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_variable($2.id,iname,$1); + Status = oldstatus; + } + } else { + char *tm = 0; + int oldstatus = Status; + if ($1->status & STAT_READONLY) { + if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"",""))) + Status = Status | STAT_READONLY; + } + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_variable($2.id,iname,$1); + Status = oldstatus; + if (Verbose) { + fprintf(stderr,"Wrapping member data %s\n", $2.id); + } + } + } + scanner_clear_start(); + } + delete $1; + } cpp_tail { } + + | type declaration array def_args { + char *iname; + if (allow) { + int oldstatus = Status; + char *tm = 0; + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + if (Active_type) delete Active_type; + Active_type = new DataType($1); + $1->is_pointer += $2.is_pointer + 1; + $1->is_reference = $2.is_reference; + $1->arraystr = copy_string(ArrayString); + if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"",""))) + Status = STAT_READONLY; + + iname = make_name($2.id); + doc_entry = new DocDecl(iname, doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_variable($2.id,iname,$1); + Status = oldstatus; + if (!tm) + fprintf(stderr,"%s : Line %d. Warning. Array member will be read-only.\n",input_file,line_number); + } + scanner_clear_start(); + } + delete $1; + } + + +/* Static Member data */ + + | STATIC type declaration { + char *iname; + if (allow) { + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + $2->is_pointer += $3.is_pointer; + iname = make_name($3.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $3.id) iname = 0; + cplus_static_var($3.id,iname,$2); + if (Active_type) delete Active_type; + Active_type = new DataType($2); + if (Verbose) { + fprintf(stderr,"Wrapping static member data %s\n", $3.id); + } + } + scanner_clear_start(); + } + delete $2; + } cpp_tail { } + +/* Static member function */ + + | STATIC type declaration LPAREN parms RPAREN cpp_end { + char *iname; + if (allow) { + $2->is_pointer += $3.is_pointer; + $2->is_reference = $3.is_reference; + if (cplus_mode == CPLUS_PUBLIC) { + iname = make_name($3.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $3.id) iname = 0; + cplus_static_func($3.id, iname, $2, $5); + if (Verbose) + fprintf(stderr,"Wrapping static member function %s\n",$3.id); + } + scanner_clear_start(); + } + delete $2; + delete $5; + } +/* Turn on public: mode */ + + | PUBLIC COLON { + if (allow) { + cplus_mode = CPLUS_PUBLIC; + if (Verbose) + fprintf(stderr,"Public mode\n"); + scanner_clear_start(); + } + } + +/* Turn on private: mode */ + + | PRIVATE COLON { + if (allow) { + cplus_mode = CPLUS_PRIVATE; + if (Verbose) + fprintf(stderr,"Private mode\n"); + scanner_clear_start(); + } + } + +/* Turn on protected mode */ + + | PROTECTED COLON { + if (allow) { + cplus_mode = CPLUS_PROTECTED; + if (Verbose) + fprintf(stderr,"Protected mode\n"); + scanner_clear_start(); + } + } + +/* This is the new style rename */ + + | NAME LPAREN ID RPAREN { + if (allow) { + strcpy(yy_rename,$3); + Rename_true = 1; + } + } + +/* New mode */ + | NEW { + NewObject = 1; + } cpp_member { + NewObject = 0; + } + +/* C++ Enum */ + | ENUM ename LBRACE {scanner_clear_start();} cpp_enumlist RBRACE SEMI { + + // if ename was supplied. Install it as a new integer datatype. + + if (allow) { + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + if ($2) { + cplus_register_type($2); + temp_type.type = T_INT; + temp_type.is_pointer = 0; + temp_type.implicit_ptr = 0; + sprintf(temp_type.name,"int"); + temp_type.typedef_add($2,1); + } + } + } + } + | READONLY { + if (allow) + Status = Status | STAT_READONLY; + scanner_clear_start(); + } + | READWRITE { + if (allow) + Status = Status & ~(STAT_READONLY); + scanner_clear_start(); + } +/* A friend : Illegal */ + | FRIEND { + if (allow) + fprintf(stderr,"%s : Line %d. Friends are not allowed--members only! (ignored)\n", input_file, line_number); + skip_decl(); + scanner_clear_start(); + } + +/* An operator: Illegal */ + | type type_extra OPERATOR { + if (allow) + fprintf(stderr,"%s : Line %d. Operator overloading not supported (ignored).\n", input_file, line_number); + skip_decl(); + scanner_clear_start(); + } + | cond_compile { + scanner_clear_start(); + } + +/* A typedef inside a class */ + | typedef_decl { } + +/* Pragma directive */ + + | cpp_pragma { + scanner_clear_start(); + } + + +cpp_pragma : PRAGMA ID stylearg { + if (allow && (!WrapExtern)) { } + } + | PRAGMA LPAREN ID RPAREN ID stylearg { + if (allow && (!WrapExtern)) + cplus_add_pragma($3,$5,$6); + } + ; + + + +/* ---------------------------------------------------------------------- + Nested structure. This is a big ugly "hack". If we encounter + a nested structure, we're going to grab the text of its definition and + feed it back into the scanner. In the meantime, we need to grab + variable declaration information and generate the associated wrapper + code later. Yikes! + + This really only works in a limited sense. Since we use the + code attached to the nested class to generate both C/C++ code, + it can't have any SWIG directives in it. It also needs to be parsable + by SWIG or this whole thing is going to puke. + ---------------------------------------------------------------------- */ + +/* A struct sname { } id; declaration */ + + | cpptype ID LBRACE { start_line = line_number; skip_brace(); + } nested_decl SEMI { + + if (cplus_mode == CPLUS_PUBLIC) { + cplus_register_type($2); + if ($5.id) { + if (strcmp($1,"class") == 0) { + fprintf(stderr,"%s : Line %d. Warning. Nested classes not currently supported (ignored).\n", input_file, line_number); + /* Generate some code for a new class */ + } else { + Nested *n = new Nested; + n->code << "typedef " << $1 << " " + << CCode.get() << " $classname_" << $5.id << ";\n"; + n->name = copy_string($5.id); + n->line = start_line; + n->type = new DataType; + n->type->type = T_USER; + n->type->is_pointer = $5.is_pointer; + n->type->is_reference = $5.is_reference; + n->next = 0; + add_nested(n); + } + } + } + } +/* An unnamed structure definition */ + | cpptype LBRACE { start_line = line_number; skip_brace(); + } declaration SEMI { + if (cplus_mode == CPLUS_PUBLIC) { + if (strcmp($1,"class") == 0) { + fprintf(stderr,"%s : Line %d. Warning. Nested classes not currently supported (ignored)\n", input_file, line_number); + /* Generate some code for a new class */ + } else { + /* Generate some code for a new class */ + + Nested *n = new Nested; + n->code << "typedef " << $1 << " " + << CCode.get() << " $classname_" << $4.id << ";\n"; + n->name = copy_string($4.id); + n->line = start_line; + n->type = new DataType; + n->type->type = T_USER; + n->type->is_pointer = $4.is_pointer; + n->type->is_reference = $4.is_reference; + n->next = 0; + add_nested(n); + + } + } + } +/* An empty class declaration */ + | cpptype ID SEMI { + if (cplus_mode == CPLUS_PUBLIC) { + cplus_register_type($2); + } + } + +/* Other miscellaneous errors */ + | type stars LPAREN { + skip_decl(); + fprintf(stderr,"%s : Line %d. Function pointers not currently supported (ignored).\n", input_file, line_number); + + } + | strict_type LPAREN STAR { + skip_decl(); + fprintf(stderr,"%s : Line %d. Function pointers not currently supported (ignored).\n", input_file, line_number); + + } + | ID LPAREN STAR { + skip_decl(); + fprintf(stderr,"%s : Line %d. Function pointers not currently supported (ignored).\n", input_file, line_number); + + } + | doc_enable { } + | SEMI { } + ; + +nested_decl : declaration { $$ = $1;} + | empty { $$.id = 0; } + ; + +type_extra : stars {} + | AND {} + | empty {} + ; + +cpp_tail : SEMI { } + | COMMA declaration def_args { + if (allow) { + int oldstatus = Status; + char *tm; + + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + temp_typeptr = new DataType(Active_type); + temp_typeptr->is_pointer += $2.is_pointer; + if (Verbose) { + fprintf(stderr,"Wrapping member variable : %s\n",$2.id); + } + Stat_var++; + doc_entry = new DocDecl($2.id,doc_stack[doc_stack_top]); + if (temp_typeptr->status & STAT_READONLY) { + if (!(tm = typemap_lookup("memberin",typemap_lang,temp_typeptr,$2.id,"",""))) + Status = Status | STAT_READONLY; + } + cplus_variable($2.id,(char *) 0,temp_typeptr); + Status = oldstatus; + delete temp_typeptr; + } + scanner_clear_start(); + } + } cpp_tail { } + | COMMA declaration array def_args { + if (allow) { + int oldstatus = Status; + char *tm; + + init_language(); + if (cplus_mode == CPLUS_PUBLIC) { + temp_typeptr = new DataType(Active_type); + temp_typeptr->is_pointer += $2.is_pointer; + if (Verbose) { + fprintf(stderr,"Wrapping member variable : %s\n",$2.id); + } + Stat_var++; + if (!(tm = typemap_lookup("memberin",typemap_lang,temp_typeptr,$2.id,"",""))) + Status = Status | STAT_READONLY; + doc_entry = new DocDecl($2.id,doc_stack[doc_stack_top]); + if (temp_typeptr->status & STAT_READONLY) Status = Status | STAT_READONLY; + cplus_variable($2.id,(char *) 0,temp_typeptr); + Status = oldstatus; + if (!tm) + fprintf(stderr,"%s : Line %d. Warning. Array member will be read-only.\n",input_file,line_number); + delete temp_typeptr; + } + scanner_clear_start(); + } + } cpp_tail { } + ; + +cpp_end : cpp_const SEMI { + CCode = ""; + } + | cpp_const LBRACE { skip_brace(); } + ; + +cpp_vend : cpp_const SEMI { CCode = ""; } + | cpp_const EQUAL definetype SEMI { CCode = ""; } + | cpp_const LBRACE { skip_brace(); } + ; + +cpp_enumlist : cpp_enumlist COMMA cpp_edecl {} + | cpp_edecl {} + ; + +cpp_edecl : ID { + if (allow) { + if (cplus_mode == CPLUS_PUBLIC) { + if (Verbose) { + fprintf(stderr,"Creating enum value %s\n", $1); + } + Stat_const++; + temp_typeptr = new DataType(T_INT); + doc_entry = new DocDecl($1,doc_stack[doc_stack_top]); + cplus_declare_const($1, (char *) 0, temp_typeptr, (char *) 0); + delete temp_typeptr; + scanner_clear_start(); + } + } + } + | ID EQUAL etype { + if (allow) { + if (cplus_mode == CPLUS_PUBLIC) { + if (Verbose) { + fprintf(stderr, "Creating enum value %s = %s\n", $1, $3.id); + } + Stat_const++; + temp_typeptr = new DataType(T_INT); + doc_entry = new DocDecl($1,doc_stack[doc_stack_top]); + cplus_declare_const($1,(char *) 0, temp_typeptr,(char *) 0); +// OLD : Bug with value cplus_declare_const($1,(char *) 0, temp_typeptr,$3.id); + delete temp_typeptr; + scanner_clear_start(); + } + } + } + | NAME LPAREN ID RPAREN ID { + if (allow) { + if (cplus_mode == CPLUS_PUBLIC) { + if (Verbose) { + fprintf(stderr,"Creating enum value %s\n", $5); + } + Stat_const++; + temp_typeptr = new DataType(T_INT); + doc_entry = new DocDecl($3,doc_stack[doc_stack_top]); + cplus_declare_const($5, $3, temp_typeptr, (char *) 0); + delete temp_typeptr; + scanner_clear_start(); + } + } + } + | NAME LPAREN ID RPAREN ID EQUAL etype { + if (allow) { + if (cplus_mode == CPLUS_PUBLIC) { + if (Verbose) { + fprintf(stderr, "Creating enum value %s = %s\n", $5, $7.id); + } + Stat_const++; + temp_typeptr = new DataType(T_INT); + doc_entry = new DocDecl($3,doc_stack[doc_stack_top]); + cplus_declare_const($5,$3, temp_typeptr, (char *) 0); +// Old : bug with value cplus_declare_const($5,$3, temp_typeptr,$7.id); + delete temp_typeptr; + scanner_clear_start(); + } + } + } + | cond_compile cpp_edecl { } + | empty { } + ; + +inherit : COLON base_list { + $$ = $2; + } + | empty { + $$.names = (char **) 0; + $$.count = 0; + } + ; + +base_list : base_specifier { + int i; + $$.names = new char *[NI_NAMES]; + $$.count = 0; + for (i = 0; i < NI_NAMES; i++){ + $$.names[i] = (char *) 0; + } + if ($1) { + $$.names[$$.count] = copy_string($1); + $$.count++; + } + } + + | base_list COMMA base_specifier { + $$ = $1; + if ($3) { + $$.names[$$.count] = copy_string($3); + $$.count++; + } + } + ; + +base_specifier : ID { + fprintf(stderr,"%s : Line %d. No access specifier given for base class %s (ignored).\n", + input_file,line_number,$1); + $$ = (char *) 0; + } + | VIRTUAL ID { + fprintf(stderr,"%s : Line %d. No access specifier given for base class %s (ignored).\n", + input_file,line_number,$2); + $$ = (char *) 0; + } + | VIRTUAL access_specifier ID { + if (strcmp($2,"public") == 0) { + $$ = $3; + } else { + fprintf(stderr,"%s : Line %d. %s inheritance not supported (ignored).\n", + input_file,line_number,$2); + $$ = (char *) 0; + } + } + | access_specifier ID { + if (strcmp($1,"public") == 0) { + $$ = $2; + } else { + fprintf(stderr,"%s : Line %d. %s inheritance not supported (ignored).\n", + input_file,line_number,$1); + $$ = (char *) 0; + } + } + | access_specifier VIRTUAL ID { + if (strcmp($1,"public") == 0) { + $$ = $3; + } else { + fprintf(stderr,"%s : Line %d. %s inheritance not supported (ignored).\n", + input_file,line_number,$1); + $$ = (char *) 0; + } + } + ; + +access_specifier : PUBLIC { $$ = "public"; } + | PRIVATE { $$ = "private"; } + | PROTECTED { $$ = "protected"; } + ; + + +cpptype : CLASS { $$ = "class"; } + | STRUCT { $$ = "struct"; } + | UNION {$$ = "union"; } + ; + +cpp_const : CONST {} + | THROW LPAREN parms RPAREN { delete $3;} + | empty {} + ; + +/* Constructor initializer */ + +ctor_end : cpp_const ctor_initializer SEMI { + CCode = ""; + } + | cpp_const ctor_initializer LBRACE { skip_brace(); } + ; + +ctor_initializer : COLON mem_initializer_list {} + | empty {} + ; + +mem_initializer_list : mem_initializer { } + | mem_initializer_list COMMA mem_initializer { } + ; + +mem_initializer : ID LPAREN expr_list RPAREN { } + | ID LPAREN RPAREN { } + ; + +expr_list : expr { } + | expr_list COMMA expr { } + ; + + +/**************************************************************/ +/* Objective-C parsing */ +/**************************************************************/ + +objective_c : OC_INTERFACE ID objc_inherit { + ObjCClass = 1; + init_language(); + cplus_mode = CPLUS_PROTECTED; + sprintf(temp_name,"CPP_CLASS:%s\n",$2); + if (add_symbol(temp_name,(DataType *) 0, (char *) 0)) { + fprintf(stderr,"%s : Line %d. @interface %s is multiple defined.\n", + input_file,line_number,$2); + FatalError(); + } + // Create a new documentation entry + doc_entry = new DocClass($2,doc_parent()); + doc_stack_top++; + doc_stack[doc_stack_top] = doc_entry; + scanner_clear_start(); + cplus_open_class($2, (char *) 0, ""); // Open up a new C++ class + } LBRACE objc_data RBRACE objc_methods OC_END { + if ($3) { + char *inames[1]; + inames[0] = $3; + cplus_inherit(1,inames); + } + // Restore original doc entry for this class + doc_entry = doc_stack[doc_stack_top]; + cplus_class_close($2); + doc_entry = 0; + doc_stack_top--; + cplus_mode = CPLUS_PUBLIC; + ObjCClass = 0; + delete $2; + delete $3; + } +/* An obj-c category declaration */ + | OC_INTERFACE ID LPAREN ID RPAREN objc_protolist { + ObjCClass = 1; + init_language(); + cplus_mode = CPLUS_PROTECTED; + doc_entry = cplus_set_class($2); + if (!doc_entry) { + doc_entry = new DocClass($2,doc_parent()); + } + doc_stack_top++; + doc_stack[doc_stack_top] = doc_entry; + scanner_clear_start(); + } objc_methods OC_END { + cplus_unset_class(); + doc_entry = 0; + doc_stack_top--; + } + | OC_IMPLEMENT { skip_to_end(); } + | OC_PROTOCOL { skip_to_end(); } + | OC_CLASS ID initlist SEMI { + char *iname = make_name($2); + init_language(); + lang->cpp_class_decl($2,iname,""); + for (int i = 0; i <$3.count; i++) { + if ($3.names[i]) { + iname = make_name($3.names[i]); + lang->cpp_class_decl($3.names[i],iname,""); + delete [] $3.names[i]; + } + } + delete [] $3.names; + } + ; + +objc_inherit : COLON ID objc_protolist { $$ = $2;} + | objc_protolist empty { $$ = 0; } + ; + + +objc_protolist : LESSTHAN { skip_template(); + CCode.strip(); // Strip whitespace + CCode.replace("<","< "); + CCode.replace(">"," >"); + $$ = CCode.get(); + } + | empty { + $$ = ""; + } + ; + +objc_data : objc_vars objc_data { } + | OC_PUBLIC { + cplus_mode = CPLUS_PUBLIC; + } objc_data { } + | OC_PRIVATE { + cplus_mode = CPLUS_PRIVATE; + } objc_data { } + | OC_PROTECTED { + cplus_mode = CPLUS_PROTECTED; + } objc_data { } + | error { + if (!Error) { + skip_decl(); + { + static int last_error_line = -1; + if (last_error_line != line_number) { + fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number); + FatalError(); + last_error_line = line_number; + } + Error = 1; + } + } + } objc_data { } + | empty { } + ; + +objc_vars : objc_var objc_vartail SEMI { + + } + ; + +/* An objective-C member variable */ + +objc_var : type declaration { + if (cplus_mode == CPLUS_PUBLIC) { + int oldstatus = Status; + char *tm; + char *iname; + if (Active_type) delete Active_type; + Active_type = new DataType($1); + $1->is_pointer += $2.is_pointer; + $1->is_reference = $2.is_reference; + if ($1->status & STAT_READONLY) { + if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"",""))) + Status = Status | STAT_READONLY; + } + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_variable($2.id,iname,$1); + Status = oldstatus; + } + scanner_clear_start(); + delete $1; + } + | type declaration array { + if (cplus_mode == CPLUS_PUBLIC) { + int oldstatus = Status; + char *tm, *iname; + if (Active_type) delete Active_type; + Active_type = new DataType($1); + $1->is_pointer += $2.is_pointer; + $1->is_reference = $2.is_reference; + $1->arraystr = copy_string(ArrayString); + if ($1->status & STAT_READONLY) { + if (!(tm = typemap_lookup("memberin",typemap_lang,$1,$2.id,"",""))) + Status = Status | STAT_READONLY; + } + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_variable($2.id,iname,$1); + Status = oldstatus; + } + scanner_clear_start(); + delete $1; + } + | NAME LPAREN ID RPAREN { + strcpy(yy_rename,$3); + Rename_true = 1; + } objc_var { }; + +objc_vartail : COMMA declaration objc_vartail { + if (cplus_mode == CPLUS_PUBLIC) { + int oldstatus = Status; + char *tm, *iname; + DataType *t = new DataType (Active_type); + t->is_pointer += $2.is_pointer; + t->is_reference = $2.is_reference; + if (t->status & STAT_READONLY) { + if (!(tm = typemap_lookup("memberin",typemap_lang,t,$2.id,"",""))) + Status = Status | STAT_READONLY; + } + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_variable($2.id,iname,t); + Status = oldstatus; + delete t; + } + scanner_clear_start(); + } + | COMMA declaration array objc_vartail { + char *iname; + if (cplus_mode == CPLUS_PUBLIC) { + int oldstatus = Status; + char *tm; + DataType *t = new DataType (Active_type); + t->is_pointer += $2.is_pointer; + t->is_reference = $2.is_reference; + t->arraystr = copy_string(ArrayString); + if (t->status & STAT_READONLY) { + if (!(tm = typemap_lookup("memberin",typemap_lang,t,$2.id,"",""))) + Status = Status | STAT_READONLY; + } + iname = make_name($2.id); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $2.id) iname = 0; + cplus_variable($2.id,iname,t); + Status = oldstatus; + delete t; + } + scanner_clear_start(); + } + | empty { } + ; + +objc_methods : objc_method objc_methods { }; + | ADDMETHODS LBRACE { + AddMethods = 1; + } objc_methods RBRACE { + AddMethods = 0; + } + | NAME LPAREN ID RPAREN { + strcpy(yy_rename,$3); + Rename_true = 1; + } objc_methods { } + | error { + skip_decl(); + if (!Error) { + { + static int last_error_line = -1; + if (last_error_line != line_number) { + fprintf(stderr,"%s : Line %d. Syntax error in input.\n", input_file, line_number); + FatalError(); + last_error_line = line_number; + } + Error = 1; + } + } + } objc_methods { } + | empty { } + ; + +objc_method : MINUS objc_ret_type ID objc_args objc_end { + char *iname; + // An objective-C instance function + // This is like a C++ member function + + if (strcmp($3,objc_destruct) == 0) { + // This is an objective C destructor + doc_entry = new DocDecl($3,doc_stack[doc_stack_top]); + cplus_destructor($3,(char *) 0); + } else { + iname = make_name($3); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $3) iname = 0; + cplus_member_func($3,iname,$2,$4,0); + scanner_clear_start(); + delete $2; + delete $3; + delete $4; + } + } + | PLUS objc_ret_type ID objc_args objc_end { + char *iname; + // An objective-C class function + // This is like a c++ static member function + if (strcmp($3,objc_construct) == 0) { + // This is an objective C constructor + doc_entry = new DocDecl($3,doc_stack[doc_stack_top]); + cplus_constructor($3,0,$4); + } else { + iname = make_name($3); + doc_entry = new DocDecl(iname,doc_stack[doc_stack_top]); + if (iname == $3) iname = 0; + cplus_static_func($3,iname,$2,$4); + } + scanner_clear_start(); + delete $2; + delete $3; + delete $4; + } + ; + +objc_end : SEMI { CCode = ""; } + | LBRACE { skip_brace(); } + ; + +objc_ret_type : LPAREN type RPAREN { + $$ = $2; + } + | LPAREN type stars RPAREN { + $$ = $2; + $$->is_pointer += $3; + } + | empty { /* Empty type means "id" type */ + $$ = new DataType(T_VOID); + sprintf($$->name,"id"); + $$->is_pointer = 1; + $$->implicit_ptr = 1; + } + ; + +objc_arg_type : LPAREN parm RPAREN { + $$ = new DataType($2->t); + delete $2; + } + | empty { + $$ = new DataType(T_VOID); + sprintf($$->name,"id"); + $$->is_pointer = 1; + $$->implicit_ptr = 1; + } + ; + +objc_args : objc_args objc_separator objc_arg_type ID { + Parm *p= new Parm($3,$4); + p->objc_separator = $2; + $$ = $1; + $$->append(p); + } + | empty { + $$ = new ParmList; + } + ; + +objc_separator : COLON { $$ = copy_string(":"); } + | ID COLON { $$ = new char[strlen($1)+2]; + strcpy($$,$1); + strcat($$,":"); + delete $1; + } + ; + +/* Miscellaneous stuff */ + +/* Documentation style list */ + +stylelist : ID stylearg styletail { + $$ = $3; + $$.names[$$.count] = copy_string($1); + $$.values[$$.count] = copy_string($2); + format_string($$.values[$$.count]); + $$.count++; + } + ; + + +styletail : styletail COMMA ID stylearg { + $$ = $1; + $$.names[$$.count] = copy_string($3); + $$.values[$$.count] = copy_string($4); + format_string($$.values[$$.count]); + $$.count++; + } + | empty { + $$.names = new char *[NI_NAMES]; + $$.values = new char *[NI_NAMES]; + $$.count = 0; + } + ; + +stylearg : EQUAL NUM_INT { + $$ = $2; + } + | EQUAL STRING { + $$ = $2; + } + | empty { + $$ = 0; + } + ; + + +/* -------------------------------------------------------------- + * Type-map parameters + * -------------------------------------------------------------- */ + +tm_method : ID { + $$ = $1; + } + | CONST { + $$ = copy_string("const"); + } + ; + +tm_list : typemap_parm tm_tail { + $$ = $1; + $$->next = $2; + } + ; + +tm_tail : COMMA typemap_parm tm_tail { + $$ = $2; + $$->next = $3; + } + | empty { $$ = 0;} + ; + +typemap_parm : type typemap_name { + if (InArray) { + $1->is_pointer++; + $1->arraystr = copy_string(ArrayString); + } + $$ = new TMParm; + $$->p = new Parm($1,$2); + $$->p->call_type = 0; + $$->args = tm_parm; + delete $1; + delete $2; + } + + | type stars typemap_name { + $$ = new TMParm; + $$->p = new Parm($1,$3); + $$->p->t->is_pointer += $2; + $$->p->call_type = 0; + if (InArray) { + $$->p->t->is_pointer++; + $$->p->t->arraystr = copy_string(ArrayString); + } + $$->args = tm_parm; + delete $1; + delete $3; + } + + | type AND typemap_name { + $$ = new TMParm; + $$->p = new Parm($1,$3); + $$->p->t->is_reference = 1; + $$->p->call_type = 0; + $$->p->t->is_pointer++; + if (!CPlusPlus) { + fprintf(stderr,"%s : Line %d. Warning. Use of C++ Reference detected. Use the -c++ option.\n", input_file, line_number); + } + $$->args = tm_parm; + delete $1; + delete $3; + } + | type LPAREN stars typemap_name RPAREN LPAREN parms RPAREN { + fprintf(stderr,"%s : Line %d. Error. Function pointer not allowed (remap with typedef).\n", input_file, line_number); + FatalError(); + $$ = new TMParm; + $$->p = new Parm($1,$4); + $$->p->t->type = T_ERROR; + $$->p->name = copy_string($4); + strcpy($$->p->t->name,""); + $$->args = tm_parm; + delete $1; + delete $4; + delete $7; + } + ; + +typemap_name : ID typemap_args { + $$ = $1; + InArray = 0; + } + | ID array { + ArrayBackup = ""; + ArrayBackup << ArrayString; + } typemap_args { + $$ = $1; + InArray = $2; + ArrayString = ""; + ArrayString << ArrayBackup; + } + | array { + ArrayBackup = ""; + ArrayBackup << ArrayString; + } typemap_args { + $$ = new char[1]; + $$[0] = 0; + InArray = $1; + ArrayString = ""; + ArrayString << ArrayBackup; + } + | typemap_args { $$ = new char[1]; + $$[0] = 0; + InArray = 0; + } + ; + +typemap_args : LPAREN parms RPAREN { + tm_parm = $2; + } + | empty { + tm_parm = 0; + } + ; + +idstring : ID {$$ = $1;} + | STRING { $$ = $1;} + ; + + +/* User defined directive */ + +user_directive : USERDIRECTIVE LPAREN parms RPAREN uservalue { } + | USERDIRECTIVE uservalue { } + ; + +uservalue : ID SEMI { } + | STRING SEMI { } + | LBRACE RBRACE { } + ; + + + +/* Parsing of expressions, but only for throw away code */ + +/* Might need someday +dummyexpr : NUM_INT { } + | NUM_FLOAT { } + | NUM_UNSIGNED { } + | NUM_LONG { } + | NUM_ULONG { } + | SIZEOF LPAREN type RPAREN { } + | ID { } + | dummyexpr PLUS dummyexpr { } + | dummyexpr MINUS dummyexpr { } + | dummyexpr STAR dummyexpr { } + | dummyexpr SLASH dummyexpr { } + | dummyexpr AND dummyexpr { } + | dummyexpr OR dummyexpr { } + | dummyexpr XOR dummyexpr { } + | dummyexpr LSHIFT dummyexpr { } + | dummyexpr RSHIFT dummyexpr { } + | MINUS dummyexpr %prec UMINUS { } + | NOT dummyexpr { } + | LPAREN dummyexpr RPAREN { } + ; + + */ + + +empty : ; + +%% + +void error_recover() { + int c; + c = yylex(); + while ((c > 0) && (c != SEMI)) + c = yylex(); +} + +/* Called by the parser (yyparse) when an error is found.*/ +void yyerror (char *) { + // Fprintf(stderr,"%s : Line %d. Syntax error.\n", input_file, line_number); + // error_recover(); +} + diff --git a/SWIG/Source/SWIG1.1/scanner.cxx b/SWIG/Source/SWIG1.1/scanner.cxx new file mode 100644 index 000000000..8f88562f0 --- /dev/null +++ b/SWIG/Source/SWIG1.1/scanner.cxx @@ -0,0 +1,1381 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/************************************************************************* + * $Header$ + * scanner.c + * + * Dave Beazley + * January 1996 + * + * Input scanner. This scanner finds and returns tokens + * for the wrapper generator. Since using lex/flex from + * C++ is so F'ed up, I've written this function to replace + * them entirely. It's not as fast, but hopefully it will + * eliminate alot of compilation problems. + * + *************************************************************************/ + + +#include "internal.h" +#include "parser.h" +#include +#include + +#define YYBSIZE 8192 + +struct InFile { + FILE *f; + int line_number; + char *in_file; + int extern_mode; + int force_extern; + struct InFile *prev; +}; + +// This structure is used for managing code fragments as +// might be used by the %inline directive and handling of +// nested structures. + +struct CodeFragment { + char *text; + int line_number; + CodeFragment *next; +}; + +InFile *in_head; + +FILE *LEX_in = NULL; + +static String header; +static String comment; + String CCode; // String containing C code +static char *yybuffer; +static int lex_pos = 0; +static int lex_len = 0; +static char *inline_yybuffer = 0; +static int inline_lex_pos = 0; +static int inline_lex_len = 0; +static int inline_line_number = 0; +static CodeFragment *fragments = 0; // Code fragments + +static +char yytext[YYBSIZE]; +static int yylen = 0; +int line_number = 1; +int column = 1; +int column_start = 1; +char *input_file; +int start_line = 0; +static int comment_start; +static int scan_init = 0; +static int num_brace = 0; +static int last_brace = 0; +static int in_define = 0; +static int define_first_id = 0; /* Set when looking for first identifier of a define */ +extern int Error; + + +/************************************************************** + * scanner_init() + * + * Initialize buffers + **************************************************************/ + +void scanner_init() { + + yybuffer = (char *) malloc(YYBSIZE); + scan_init = 1; +} + +/************************************************************** + * scanner_file(FILE *f) + * + * Start reading from new file + **************************************************************/ +void scanner_file(FILE *f) { + InFile *in; + + in = new InFile; + in->f = f; + in->in_file = input_file; + in->extern_mode = WrapExtern; + in->force_extern = ForceExtern; + if (in_head) in_head->line_number = line_number+1; + if (!in_head) in->prev = 0; + else in->prev = in_head; + in_head = in; + LEX_in = f; + line_number = 1; +} + +/************************************************************** + * scanner_close() + * + * Close current input file and go to next + **************************************************************/ + +void scanner_close() { + + InFile *p; + static int lib_insert = 0; + fclose(LEX_in); + if (!in_head) return; + p = in_head->prev; + if (p != 0) { + LEX_in = p->f; + line_number = p->line_number; + input_file = p->in_file; + WrapExtern = p->extern_mode; + if (!WrapExtern) remove_symbol("SWIGEXTERN"); + ForceExtern = p->force_extern; + } else { + LEX_in = NULL; + } + delete in_head; + in_head = p; + + // if LEX_in is NULL it means we're done with the interface file. We're now + // going to grab all of the library files. + + if ((!LEX_in) && (!lib_insert)) { + library_insert(); + lib_insert = 1; + } + +} + +/************************************************************** + * char nextchar() + * + * gets next character from input. + * If we're in inlining mode, we actually retrieve a character + * from inline_yybuffer instead. + **************************************************************/ + +char nextchar() { + + char c = 0; + + if (Inline) { + if (inline_lex_pos >= inline_lex_len) { + // Done with inlined code. Check to see if we have any + // new code fragments. If so, switch to them. + delete inline_yybuffer; + if (fragments) { + CodeFragment *f; + inline_yybuffer = fragments->text; + inline_lex_pos = 1; + inline_lex_len = strlen(fragments->text); + line_number = fragments->line_number; + f = fragments->next; + delete fragments; + fragments = f; + c = inline_yybuffer[0]; + } else { + c = 0; + Inline = 0; + line_number = inline_line_number; // Restore old line number + } + } else { + inline_lex_pos++; + c = inline_yybuffer[inline_lex_pos-1]; + } + } + if (!Inline) { + if (lex_pos >= lex_len) { + if (!LEX_in) { + SWIG_exit(1); + } + while(fgets(yybuffer, YYBSIZE, LEX_in) == NULL) { + scanner_close(); // Close current input file + if (!LEX_in) return 0; // No more, we're outta here + } + lex_len = strlen(yybuffer); + lex_pos = 0; + } + + lex_pos++; + c = yybuffer[lex_pos-1]; + } + + if (yylen >= YYBSIZE) { + fprintf(stderr,"** FATAL ERROR. Buffer overflow in scanner.cxx.\nReport this to swig@cs.utah.edu.\n"); + SWIG_exit(1); + } + yytext[yylen] = c; + yylen++; + if (c == '\n') { + line_number++; + column = 1; + } else { + column++; + } + return(c); +} + +void retract(int n) { + int i, j, c; + + for (i = 0; i < n; i++) { + if (Inline) { + inline_lex_pos--; + if (inline_lex_pos < 0) { + fprintf(stderr,"Internal scanner error. inline_lex_pos < 0\n"); + SWIG_exit(1); + } + } + else lex_pos--; + yylen--; + column--; + if (yylen >= 0) { + if (yytext[yylen] == '\n') { + line_number--; + // Figure out what column we're in + c = yylen-1; + j = 1; + while (c >= 0){ + if (yytext[c] == '\n') break; + j++; + c--; + } + column = j; + } + } + } + if (yylen < 0) yylen = 0; +} + +/************************************************************** + * start_inline(char *text, int line) + * + * This grabs a chunk of text and tries to inline it into + * the current file. (This is kind of wild, but cool when + * it works). + * + * If we're already in inlining mode, we will save the code + * as a new fragment. + **************************************************************/ + +void start_inline(char *text, int line) { + + if (Inline) { + + // Already processing a code fragment, simply hang on + // to this one for later. + + CodeFragment *f,*f1; + + // Add a new code fragment to our list + f = new CodeFragment; + f->text = copy_string(text); + f->line_number = line; + f->next = 0; + if (!fragments) fragments = f; + else { + f1 = fragments; + while (f1->next) f1 = f1->next; + f1->next = f; + } + } else { + + // Switch our scanner over to process text from a string. + // Save current line number and other information however. + + inline_yybuffer = copy_string(text); + inline_lex_len = strlen(text); + inline_lex_pos = 0; + inline_line_number = line_number; // Make copy of old line number + line_number = line; + Inline = 1; + } +} + +/************************************************************** + * yycomment(char *, int line) + * + * Inserts a comment into a documentation entry. + **************************************************************/ + +void yycomment(char *s, int line, int col) { + comment_handler->add_comment(s,line,col,input_file); +} + +/************************************************************** + * void skip_brace(void) + * + * Found a {. + * Skip all characters until we find a matching closed }. + * + * This function is used to skip over inlined C code and other + * garbage found in interface files. + ***************************************************************/ + +void skip_brace(void) { + + char c; + CCode = "{"; + while (num_brace > last_brace) { + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Missing '}'. Reached end of input.\n", + input_file, line_number); + FatalError(); + return; + } + CCode << c; + if (c == '{') num_brace++; + if (c == '}') num_brace--; + yylen = 0; + } +} + + +/************************************************************** + * void skip_template(void) + * + * Found a <. + * Skip all characters until we find a matching closed >. + * + * This function is used to skip over C++ templated types + * and objective-C protocols. + ***************************************************************/ + +void skip_template(void) { + + char c; + CCode = "<"; + int num_lt = 1; + while (num_lt > 0) { + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Missing '>'. Reached end of input.\n", + input_file, line_number); + FatalError(); + return; + } + CCode << c; + if (c == '<') num_lt++; + if (c == '>') num_lt--; + yylen = 0; + } +} + +/************************************************************** + * void skip_to_end(void) + * + * Skips to the @end directive in a Objective-C definition + **************************************************************/ + +void skip_to_end(void) { + char c; + int state = 0; + yylen = 0; + while ((c = nextchar())){ + switch(state) { + case 0: + if (c == '@') state = 1; + else yylen = 0; + break; + case 1: + if (isspace(c)) { + if (strncmp(yytext,"@end",4) == 0) return; + else { + yylen = 0; + state = 0; + } + } else { + state = 1; + } + break; + } + } + fprintf(stderr,"%s : EOF. Missing @end. Reached end of input.\n", + input_file); + FatalError(); + return; +} + +/************************************************************** + * void skip_decl(void) + * + * This tries to skip over an entire declaration. For example + * + * friend ostream& operator<<(ostream&, const char *s); + * + * or + * friend ostream& operator<<(ostream&, const char *s) { }; + * + **************************************************************/ + +void skip_decl(void) { + char c; + int done = 0; + while (!done) { + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Missing semicolon. Reached end of input.\n", + input_file, line_number); + FatalError(); + return; + } + if (c == '{') { + last_brace = num_brace; + num_brace++; + break; + } + yylen = 0; + if (c == ';') done = 1; + } + if (!done) { + while (num_brace > last_brace) { + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Missing '}'. Reached end of input.\n", + input_file, line_number); + FatalError(); + return; + } + if (c == '{') num_brace++; + if (c == '}') num_brace--; + yylen = 0; + } + } +} + +/************************************************************** + * void skip_define(void) + * + * Skips to the end of a #define statement. + * + **************************************************************/ + +void skip_define(void) { + char c; + while (in_define) { + if ((c = nextchar()) == 0) return; + if (c == '\\') in_define = 2; + if (c == '\n') { + if (in_define == 2) { + in_define = 1; + } else if (in_define == 1) { + in_define = 0; + } + } + yylen = 0; + } +} + +/************************************************************** + * int skip_cond(int inthen) + * + * Skips the false portion of an #ifdef directive. Looks + * for either a matching #else or #endif + * + * inthen is 0 or 1 depending on whether or not we're + * handling the "then" or "else" part of a conditional. + * + * Returns 1 if the else part of the #if-#endif block was + * reached. Returns 0 otherwise. Returns -1 on error. + **************************************************************/ + +int skip_cond(int inthen) { + int level = 0; /* Used to handled nested if-then-else */ + int state = 0; + char c; + int start_line; + char *file; + + file = copy_string(input_file); + start_line = line_number; + yylen = 0; + + while(1) { + switch(state) { + case 0 : + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Unterminated #if-else directive.\n", file, start_line); + FatalError(); + return -1; /* Error */ + } + if ((c == '#') || (c == '%')) { + state = 1; + } else if (isspace(c)) { + yylen =0; + state = 0; + } else { + /* Some non-whitespace character. Look for line end */ + yylen = 0; + state = 3; + } + break; + case 1: + /* Beginning of a C preprocessor statement */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Unterminated #if-else directive.\n", file, start_line); + FatalError(); + return -1; /* Error */ + } + if (c == '\n') { + state = 0; + yylen = 0; + } + else if (isspace(c)) { + state = 1; + yylen--; + } else { + state = 2; + } + break; + case 2: + /* CPP directive */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Unterminated #if-else directive.\n", file, start_line); + FatalError(); + return -1; /* Error */ + } + if ((c == ' ') || (c == '\t') || (c=='\n')) { + yytext[yylen-1] = 0; + if ((strcmp(yytext,"#ifdef") == 0) || (strcmp(yytext,"%ifdef") == 0)) { + level++; + state = 0; + } else if ((strcmp(yytext,"#ifndef") == 0) || (strcmp(yytext,"%ifndef") == 0)) { + level++; + state = 0; + } else if ((strcmp(yytext,"#if") == 0) || (strcmp(yytext,"%if") == 0)) { + level++; + state = 0; + } else if ((strcmp(yytext,"#else") == 0) || (strcmp(yytext,"%else") == 0)) { + if (level == 0) { /* Found matching else. exit */ + if (!inthen) { + /* Hmmm. We've got an "extra #else" directive here */ + fprintf(stderr,"%s : Line %d. Misplaced #else.\n", input_file, line_number); + FatalError(); + yylen = 0; + state = 0; + } else { + yylen = 0; + delete file; + return 1; + } + } else { + yylen = 0; + state = 0; + } + } else if ((strcmp(yytext,"#endif") == 0) || (strcmp(yytext,"%endif") == 0)) { + if (level <= 0) { /* Found matching endif. exit */ + yylen = 0; + delete file; + return 0; + } else { + state = 0; + yylen = 0; + level--; + } + } else if ((strcmp(yytext,"#elif") == 0) || (strcmp(yytext,"%elif") == 0)) { + if (level <= 0) { + // If we come across this, we pop it back onto the input queue and return + retract(6); + delete file; + return 0; + } else { + yylen = 0; + state = 0; + } + } else { + yylen = 0; + state = 0; + } + } + break; + case 3: + /* Non-white space. Look for line break */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : Line %d. Unterminated #if directive.\n", file, start_line); + FatalError(); + return -1; /* Error */ + } + if (c == '\n') { + yylen = 0; + state = 0; + } else { + yylen = 0; + state = 3; + } + break; + } + } +} + +/************************************************************** + * int yylook() + * + * Lexical scanner. + * See Aho,Sethi, and Ullman, pg. 106 + **************************************************************/ + +int yylook(void) { + + int state; + char c = 0; + + state = 0; + yylen = 0; + while(1) { + +/* printf("State = %d\n", state); */ + switch(state) { + + case 0 : + if((c = nextchar()) == 0) return(0); + + /* Process delimeters */ + + if (c == '\n') { + state = 0; + yylen = 0; + if (in_define == 1) { + in_define = 0; + return(ENDDEF); + } else if (in_define == 2) { + in_define = 1; + } + } else if (isspace(c)) { + state = 0; + yylen = 0; + } + + /* Look for single character symbols */ + + else if (c == '(') return (LPAREN); + else if (c == ')') return (RPAREN); + else if (c == ';') return (SEMI); + else if (c == ',') return (COMMA); + else if (c == '*') return (STAR); + else if (c == '}') { + num_brace--; + if (num_brace < 0) { + fprintf(stderr,"%s : Line %d. Error. Extraneous '}' (Ignored)\n", + input_file, line_number); + state = 0; + num_brace = 0; + } else { + return (RBRACE); + } + } + else if (c == '{') { + last_brace = num_brace; + num_brace++; + return (LBRACE); + } + else if (c == '=') return (EQUAL); + else if (c == '+') return (PLUS); + else if (c == '-') return (MINUS); + else if (c == '&') return (AND); + else if (c == '|') return (OR); + else if (c == '^') return (XOR); + else if (c == '<') state = 60; + else if (c == '>') state = 61; + else if (c == '~') return (NOT); + else if (c == '!') return (LNOT); + else if (c == '\\') { + if (in_define == 1) { + in_define = 2; + state = 0; + } else + state = 99; + } + else if (c == '[') return (LBRACKET); + else if (c == ']') return (RBRACKET); + + /* Look for multi-character sequences */ + + else if (c == '/') state = 1; // Comment (maybe) + else if (c == '\"') state = 2; // Possibly a string + else if (c == '#') state = 3; // CPP + else if (c == '%') state = 4; // Directive + else if (c == '@') state = 4; // Objective C keyword + else if (c == ':') state = 5; // maybe double colon + else if (c == '0') state = 83; // An octal or hex value + else if (c == '\'') state = 9; // A character constant + else if (c == '.') state = 100; // Maybe a number, maybe just a period + else if (isdigit(c)) state = 8; // A numerical value + else if ((isalpha(c)) || (c == '_') || (c == '$')) state = 7; + else state = 99; + break; + case 1: /* Comment block */ + if ((c = nextchar()) == 0) return(0); + if (c == '/') { + comment_start = line_number; + column_start = column; + comment = " "; + state = 10; // C++ style comment + } else if (c == '*') { + comment_start = line_number; + column_start = column; + comment = " "; + state = 11; // C style comment + } else { + retract(1); + return(SLASH); + } + break; + case 10: /* C++ style comment */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : EOF. Unterminated comment detected.\n",input_file); + FatalError(); + return 0; + } + if (c == '\n') { + comment << c; + // Add the comment to documentation + yycomment(comment.get(),comment_start, column_start); + yylen = 0; + state = 0; + if (in_define == 1) { + in_define = 0; + return(ENDDEF); + } + } else { + state = 10; + comment << c; + yylen = 0; + } + break; + case 11: /* C style comment block */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : EOF. Unterminated comment detected.\n", input_file); + FatalError(); + return 0; + } + if (c == '*') { + state = 12; + } else { + comment << c; + yylen = 0; + state = 11; + } + break; + case 12: /* Still in C style comment */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : EOF. Unterminated comment detected.\n", input_file); + FatalError(); + return 0; + } + if (c == '*') { + comment << c; + state = 12; + } else if (c == '/') { + comment << " \n"; + yycomment(comment.get(),comment_start,column_start); + yylen = 0; + state = 0; + } else { + comment << '*' << c; + yylen = 0; + state = 11; + } + break; + + case 2: /* Processing a string */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : EOF. Unterminated string detected.\n", input_file); + FatalError(); + return 0; + } + if (c == '\"') { + yytext[yylen-1] = 0; + yylval.id = copy_string(yytext+1); + return(STRING); + } else if (c == '\\') { + state = 21; /* Possibly an escape sequence. */ + break; + } else state = 2; + break; + case 21: /* An escape sequence. get next character, then go + back to processing strings */ + + if ((c = nextchar()) == 0) return 0; + state = 2; + break; + + case 3: /* a CPP directive */ + + if (( c= nextchar()) == 0) return 0; + if (c == '\n') { + retract(1); + yytext[yylen] = 0; + yylval.id = yytext; + return(POUND); + } else if ((c == ' ') || (c == '\t')) { // Ignore white space after # symbol + yytext[yylen] = 0; + yylen--; + state = 3; + } else { + yytext[yylen] = 0; + state = 31; + } + break; + case 31: + if ((c = nextchar()) == 0) return 0; + if ((c == ' ') || (c == '\t') || (c=='\n')) { + retract(1); + yytext[yylen] = 0; + if (strcmp(yytext,"#define") == 0) { + in_define = 1; + define_first_id = 1; + return(DEFINE); + } else if (strcmp(yytext,"#ifdef") == 0) { + return(IFDEF); + } else if (strcmp(yytext,"#ifndef") == 0) { + return(IFNDEF); + } else if (strcmp(yytext,"#else") == 0) { + return(ELSE); + } else if (strcmp(yytext,"#endif") == 0) { + return(ENDIF); + } else if (strcmp(yytext,"#undef") == 0) { + return(UNDEF); + } else if (strcmp(yytext,"#if") == 0) { + return(IF); + } else if (strcmp(yytext,"#elif") == 0) { + return(ELIF); + } else { + /* Some kind of "unknown CPP directive. Skip to end of the line */ + state = 32; + } + } + break; + case 32: + if ((c = nextchar()) == 0) return 0; + if (c == '\n') { + retract(1); + yytext[yylen] = 0; + yylval.id = yytext; + return(POUND); + } + state = 32; + break; + + case 4: /* A wrapper generator directive (maybe) */ + if (( c= nextchar()) == 0) return 0; + if (c == '{') { + state = 40; /* Include block */ + header = ""; + start_line = line_number; + } + else if ((isalpha(c)) || (c == '_')) state = 7; + else { + retract(1); + state = 99; + } + break; + + case 40: /* Process an include block */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : EOF. Unterminated include block detected.\n", input_file); + FatalError(); + return 0; + } + yylen = 0; + if (c == '%') state = 41; + else { + header << c; + yylen = 0; + state = 40; + } + break; + case 41: /* Still processing include block */ + if ((c = nextchar()) == 0) { + fprintf(stderr,"%s : EOF. Unterminated include block detected.\n", input_file); + FatalError(); + return 0; + } + if (c == '}') { + yylval.id = header.get(); + return(HBLOCK); + } else { + header << '%'; + header << c; + yylen = 0; + state = 40; + } + break; + + case 5: /* Maybe a double colon */ + + if (( c= nextchar()) == 0) return 0; + if ( c == ':') return DCOLON; + else { + retract(1); + return COLON; + } + + + case 60: /* shift operators */ + if ((c = nextchar()) == 0) return (0); + if (c == '<') return LSHIFT; + else { + retract(1); + return LESSTHAN; + } + break; + case 61: + if ((c = nextchar()) == 0) return (0); + if (c == '>') return RSHIFT; + else { + retract(1); + return GREATERTHAN; + } + break; + case 7: /* Identifier */ + if ((c = nextchar()) == 0) return(0); + if (isalnum(c) || (c == '_') || (c == '.') || (c == '$')) + // || (c == '.') || (c == '-')) + state = 7; + else if (c == '(') { + /* We might just be in a CPP macro definition. Better check */ + if ((in_define) && (define_first_id)) { + /* Yep. We're going to ignore the rest of it */ + skip_define(); + define_first_id = 0; + return (MACRO); + } else { + retract(1); + define_first_id = 0; + return(ID); + } + } else { + retract(1); + define_first_id = 0; + return(ID); + } + break; + case 8: /* A numerical digit */ + if ((c = nextchar()) == 0) return(0); + if (c == '.') {state = 81;} + else if ((c == 'e') || (c == 'E')) {state = 86;} + else if ((c == 'f') || (c == 'F')) { + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_FLOAT); + } + else if (isdigit(c)) { state = 8;} + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_INT); + } + break; + case 81: /* A floating pointer number of some sort */ + if ((c = nextchar()) == 0) return(0); + if (isdigit(c)) state = 81; + else if ((c == 'e') || (c == 'E')) state = 82; + else if ((c == 'f') || (c == 'F') || (c == 'l') || (c == 'L')) { + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_FLOAT); + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_FLOAT); + } + break; + case 82: + if ((c = nextchar()) == 0) return(0); + if ((isdigit(c)) || (c == '-') || (c == '+')) state = 86; + else { + retract(2); + yytext[yylen-1] = 0; + yylval.id = copy_string(yytext); + return(NUM_INT); + } + break; + case 83: + /* Might be a hexidecimal or octal number */ + if ((c = nextchar()) == 0) return(0); + if (isdigit(c)) state = 84; + else if ((c == 'x') || (c == 'X')) state = 85; + else if (c == '.') state = 81; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_INT); + } + break; + case 84: + /* This is an octal number */ + if ((c = nextchar()) == 0) return (0); + if (isdigit(c)) state = 84; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_INT); + } + break; + case 85: + /* This is an hex number */ + if ((c = nextchar()) == 0) return (0); + if ((isdigit(c)) || (c=='a') || (c=='b') || (c=='c') || + (c=='d') || (c=='e') || (c=='f') || (c=='A') || + (c=='B') || (c=='C') || (c=='D') || (c=='E') || + (c=='F')) + state = 85; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_INT); + } + break; + + case 86: + /* Rest of floating point number */ + + if ((c = nextchar()) == 0) return (0); + if (isdigit(c)) state = 86; + else if ((c == 'f') || (c == 'F') || (c == 'l') || (c == 'L')) { + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_FLOAT); + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_FLOAT); + } + /* Parse a character constant. ie. 'a' */ + break; + + case 87 : + /* A long integer of some sort */ + if ((c = nextchar()) == 0) return (0); + if ((c == 'u') || (c == 'U')) { + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_ULONG); + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_LONG); + } + + case 88: + /* An unsigned integer of some sort */ + if ((c = nextchar()) == 0) return (0); + if ((c == 'l') || (c == 'L')) { + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_ULONG); + } else { + retract(1); + yytext[yylen] = 0; + yylval.id = copy_string(yytext); + return(NUM_UNSIGNED); + } + + case 9: + if ((c = nextchar()) == 0) return (0); + if (c == '\'') { + yytext[yylen-1] = 0; + yylval.id = copy_string(yytext+1); + return(CHARCONST); + } + break; + + case 100: + if ((c = nextchar()) == 0) return (0); + if (isdigit(c)) state = 81; + else { + retract(1); + return(PERIOD); + } + break; + default: + if (!Error) { + fprintf(stderr,"%s : Line %d ::Illegal character '%c'=%d.\n",input_file, line_number,c,c); + FatalError(); + } + state = 0; + Error = 1; + return(ILLEGAL); + } + } +} + +static int check_typedef = 0; + +void scanner_check_typedef() { + check_typedef = 1; +} + +void scanner_ignore_typedef() { + check_typedef = 0; +} + + +/************************************************************** + * int yylex() + * + * Gets the lexene and returns tokens. + *************************************************************/ + +extern "C" int yylex(void) { + + int l; + + if (!scan_init) { + scanner_init(); + // if (LEX_in == NULL) LEX_in = stdin; + // scanner_file(LEX_in); + } + + l = yylook(); + + /* We got some sort of non-white space object. We set the start_line + variable unless it has already been set */ + + if (!start_line) { + start_line = line_number; + } + + /* Copy the lexene */ + + yytext[yylen] = 0; + + /* Hack to support ignoring of CPP macros */ + + if (l != DEFINE) { + define_first_id = 0; + } + + switch(l) { + + case ID: + + /* Look for keywords now */ + + if (strcmp(yytext,"int") == 0) { + yylval.type = new DataType; + yylval.type->type = T_INT; + strcpy(yylval.type->name,yytext); + return(TYPE_INT); + } + if (strcmp(yytext,"double") == 0) { + yylval.type = new DataType; + yylval.type->type = T_DOUBLE; + strcpy(yylval.type->name,yytext); + return(TYPE_DOUBLE); + } + if (strcmp(yytext,"void") == 0) { + yylval.type = new DataType; + yylval.type->type = T_VOID; + strcpy(yylval.type->name,yytext); + return(TYPE_VOID); + } + if (strcmp(yytext,"char") == 0) { + yylval.type = new DataType; + yylval.type->type = T_CHAR; + strcpy(yylval.type->name,yytext); + return(TYPE_CHAR); + } + if (strcmp(yytext,"short") == 0) { + yylval.type = new DataType; + yylval.type->type = T_SHORT; + strcpy(yylval.type->name,yytext); + return(TYPE_SHORT); + } + if (strcmp(yytext,"long") == 0) { + yylval.type = new DataType; + yylval.type->type = T_LONG; + strcpy(yylval.type->name,yytext); + return(TYPE_LONG); + } + if (strcmp(yytext,"float") == 0) { + yylval.type = new DataType; + yylval.type->type = T_FLOAT; + strcpy(yylval.type->name,yytext); + return(TYPE_FLOAT); + } + if (strcmp(yytext,"signed") == 0) { + yylval.type = new DataType; + yylval.type->type = T_SINT; + strcpy(yylval.type->name,yytext); + return(TYPE_SIGNED); + } + if (strcmp(yytext,"unsigned") == 0) { + yylval.type = new DataType; + yylval.type->type = T_UINT; + strcpy(yylval.type->name,yytext); + return(TYPE_UNSIGNED); + } + if (strcmp(yytext,"bool") == 0) { + yylval.type = new DataType; + yylval.type->type = T_BOOL; + strcpy(yylval.type->name,yytext); + return(TYPE_BOOL); + } + // C++ keywords + + if (CPlusPlus) { + if (strcmp(yytext,"class") == 0) return(CLASS); + if (strcmp(yytext,"private") == 0) return(PRIVATE); + if (strcmp(yytext,"public") == 0) return(PUBLIC); + if (strcmp(yytext,"protected") == 0) return(PROTECTED); + if (strcmp(yytext,"friend") == 0) return(FRIEND); + if (strcmp(yytext,"virtual") == 0) return(VIRTUAL); + if (strcmp(yytext,"operator") == 0) return(OPERATOR); + if (strcmp(yytext,"throw") == 0) return(THROW); + if (strcmp(yytext,"inline") == 0) return(yylex()); + if (strcmp(yytext,"template") == 0) return(TEMPLATE); + } + + // Objective-C keywords + if (ObjC) { + if (strcmp(yytext,"@interface") == 0) return (OC_INTERFACE); + if (strcmp(yytext,"@end") == 0) return (OC_END); + if (strcmp(yytext,"@public") == 0) return (OC_PUBLIC); + if (strcmp(yytext,"@private") == 0) return (OC_PRIVATE); + if (strcmp(yytext,"@protected") == 0) return (OC_PROTECTED); + if (strcmp(yytext,"@class") == 0) return(OC_CLASS); + if (strcmp(yytext,"@implementation") == 0) return(OC_IMPLEMENT); + if (strcmp(yytext,"@protocol") == 0) return(OC_PROTOCOL); + } + + // Misc keywords + + if (strcmp(yytext,"static") == 0) return(STATIC); + if (strcmp(yytext,"extern") == 0) return(EXTERN); + if (strcmp(yytext,"const") == 0) return(CONST); + if (strcmp(yytext,"struct") == 0) return(STRUCT); + if (strcmp(yytext,"union") == 0) return(UNION); + if (strcmp(yytext,"enum") == 0) return(ENUM); + if (strcmp(yytext,"sizeof") == 0) return(SIZEOF); + if (strcmp(yytext,"defined") == 0) return(DEFINED); + + // Ignored keywords + + if (strcmp(yytext,"volatile") == 0) return(yylex()); + + // SWIG directives + + if (strcmp(yytext,"%module") == 0) return(MODULE); + if (strcmp(yytext,"%init") == 0) return(INIT); + if (strcmp(yytext,"%wrapper") == 0) return(WRAPPER); + if (strcmp(yytext,"%readonly") == 0) return(READONLY); + if (strcmp(yytext,"%readwrite") == 0) return(READWRITE); + if (strcmp(yytext,"%name") == 0) return(NAME); + if (strcmp(yytext,"%rename") == 0) return(RENAME); + if (strcmp(yytext,"%include") == 0) return(INCLUDE); + if (strcmp(yytext,"%extern") == 0) return(WEXTERN); + if (strcmp(yytext,"%checkout") == 0) return(CHECKOUT); + if (strcmp(yytext,"%val") == 0) return(CVALUE); + if (strcmp(yytext,"%out") == 0) return(COUT); + + if (strcmp(yytext,"%section") == 0) { + yylval.ivalue = line_number; + return(SECTION); + } + if (strcmp(yytext,"%subsection") == 0) { + yylval.ivalue = line_number; + return(SUBSECTION); + } + if (strcmp(yytext,"%subsubsection") == 0) { + yylval.ivalue = line_number; + return (SUBSUBSECTION); + } + if (strcmp(yytext,"%title") == 0) { + yylval.ivalue = line_number; + return(TITLE); + } + if (strcmp(yytext,"%style") == 0) return(STYLE); + if (strcmp(yytext,"%localstyle") == 0) return(LOCALSTYLE); + if (strcmp(yytext,"%typedef") == 0) { + yylval.ivalue = 1; + return(TYPEDEF); + } + if (strcmp(yytext,"typedef") == 0) { + yylval.ivalue = 0; + return(TYPEDEF); + } + if (strcmp(yytext,"%alpha") == 0) return(ALPHA_MODE); + if (strcmp(yytext,"%raw") == 0) return(RAW_MODE); + if (strcmp(yytext,"%text") == 0) return(TEXT); + if (strcmp(yytext,"%native") == 0) return(NATIVE); + if (strcmp(yytext,"%disabledoc") == 0) return(DOC_DISABLE); + if (strcmp(yytext,"%enabledoc") == 0) return(DOC_ENABLE); + if (strcmp(yytext,"%ifdef") == 0) return(IFDEF); + if (strcmp(yytext,"%else") == 0) return(ELSE); + if (strcmp(yytext,"%ifndef") == 0) return(IFNDEF); + if (strcmp(yytext,"%endif") == 0) return(ENDIF); + if (strcmp(yytext,"%if") == 0) return(IF); + if (strcmp(yytext,"%elif") == 0) return(ELIF); + if (strcmp(yytext,"%pragma") == 0) return(PRAGMA); + if (strcmp(yytext,"%addmethods") == 0) return(ADDMETHODS); + if (strcmp(yytext,"%inline") == 0) return(INLINE); + if (strcmp(yytext,"%typemap") == 0) return(TYPEMAP); + if (strcmp(yytext,"%except") == 0) return(EXCEPT); + if (strcmp(yytext,"%import") == 0) return(IMPORT); + if (strcmp(yytext,"%echo") == 0) return(ECHO); + if (strcmp(yytext,"%new") == 0) return(NEW); + if (strcmp(yytext,"%apply") == 0) return(APPLY); + if (strcmp(yytext,"%clear") == 0) return(CLEAR); + if (strcmp(yytext,"%doconly") == 0) return(DOCONLY); + + // Have an unknown identifier, as a last step, we'll + // do a typedef lookup on it. + + if (check_typedef) { + if (DataType::is_typedef(yytext)) { + yylval.type = new DataType; + yylval.type->type = T_USER; + strcpy(yylval.type->name,yytext); + yylval.type->typedef_resolve(); + return(TYPE_TYPEDEF); + } + } + + yylval.id = copy_string(yytext); + return(ID); + default: + return(l); + } +} + +// -------------------------------------------------------------- +// scanner_clear_start() +// +// Clears the start of a declaration +// -------------------------------------------------------------- + +void scanner_clear_start() { + start_line = 0; +} diff --git a/SWIG/Source/SWIG1.1/sstring.cxx b/SWIG/Source/SWIG1.1/sstring.cxx new file mode 100644 index 000000000..15046255c --- /dev/null +++ b/SWIG/Source/SWIG1.1/sstring.cxx @@ -0,0 +1,587 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" +#include + +//----------------------------------------------------------------------- +// char *copy_string(char *str) +// +// Makes a copy of string str. Returns a pointer to it. +//----------------------------------------------------------------------- + +char *copy_string(char *str) { + char *res = 0; + if (str) { + res = new char[strlen(str)+1]; + strcpy(res,str); + } + return res; +} + +//----------------------------------------------------------------------- +// void format_string(char *str) +// +// Replace all of the escape sequences in the string str. It is +// assumed that the new string is smaller than the original! +//----------------------------------------------------------------------- + +void format_string(char *str) { + char *newstr, *c,*c1; + int state; + if (!str) return; + newstr = copy_string(str); + c = newstr; + c1 = str; + state = 0; + while (*c) { + switch(state) { + case 0: + if (*c == '\\') + state = 1; + else { + *(c1++) = *c; + state = 0; + } + break; + case 1: + // We're in a simple escape sequence figure out what to do + switch(*c) { + case 'n': + *(c1++) = '\n'; + break; + case 'f': + *(c1++) = '\f'; + break; + case 'r': + *(c1++) = '\r'; + break; + case 't': + *(c1++) = '\t'; + break; + case '\\': + *(c1++) = '\\'; + break; + case '\"': + *(c1++) = '\"'; + break; + case '\'': + *(c1++) = '\''; + break; + default: + *(c1++) = '\\'; + *(c1++) = *c; + } + state = 0; + break; + default: + *(c1++) = *c; + state = 0; + } + c++; + } + *c1 = 0; + delete newstr; +} + +// --------------------------------------------------------------------------- +// $Header$ +// sstring.cxx +// +// SWIG String class. +// This class is used to construct long strings when writing +// wrapper functions. It also "mimicks" the C++ streams I/O +// library for creating strings. For example : +// +// str << "hi there" << 3 << "\n"; +// +// Will append the given strings to str. +// +// The idea here is to provide a mechanism for writing wrapper +// functions as strings before writing them out to a file. +// +// --------------------------------------------------------------------------- +#define INIT_MAXSIZE 64 + +// --------------------------------------------------------------- +// Pools. This is a list of available strings for memory allocation +// and deletion. +// --------------------------------------------------------------- + +struct StrMem { + char *str; + int len; +}; + +#define POOLSIZE 100 + +static StrMem pool[POOLSIZE]; +static int pool_index = 0; + +// Returns an item from the pool that can accomodate len +static char *get_pool(int len, int &newlen) { + int i,j; + char *nc; + if (pool_index < 1) { + newlen = len; + return new char[len]; + } + i = pool_index-1; + j = 0; + while(i >= 0) { + if ((pool[i].len >= len) && (pool[i].len <= 4*len)) { + nc = pool[i].str; + newlen = pool[i].len; + pool[i].str = pool[pool_index-1].str; + pool[i].len = pool[pool_index-1].len; + pool_index--; + return nc; + } + j++; + i--; + } + newlen = len; + return new char[len]; +} + +// Puts an item onto the pool + +static void put_pool(char *str, int len) { + if (len < INIT_MAXSIZE) { + delete [] str; + return; + } + if (pool_index == POOLSIZE) { + delete [] pool[pool_index-1].str; + pool_index--; + } + pool[pool_index].str = str; + pool[pool_index].len = len; + if (pool_index != POOLSIZE) + pool_index++; +} + +// --------------------------------------------------------------- +// String::String() +// +// Create a new string with nothing in it +// --------------------------------------------------------------- + +String::String() { + maxsize = INIT_MAXSIZE; + str = get_pool(maxsize,maxsize); // May return a pool that is larger + str[0] = 0; + len = 0; +} + +// --------------------------------------------------------------- +// String::String(const char *s) +// +// Create a new string copied from a normal C-style string +// --------------------------------------------------------------- + +String::String(const char *s) { + int max = INIT_MAXSIZE; + int l = 0; + if (s) { + l = (int) strlen(s); + if ((l+1) > max) max = l+1; + } + str = get_pool(max,maxsize); + if (s) { + strcpy(str,s); + len = l; + } else { + str[0] = 0; + len = 0; + } +} + +// --------------------------------------------------------------- +// String::~String(const char *s) +// +// Destroy a string +// --------------------------------------------------------------- + +String::~String() { + put_pool(str,maxsize); +} + +// --------------------------------------------------------------- +// String::add(const char *newstr) +// +// Concatenate newstr onto the current string +// --------------------------------------------------------------- + +void String::add(const char *newstr) { + int newlen; + char *nstr = 0; + int newmaxsize; + int l; + + l = (int) strlen(newstr); + newlen = len+l + 1; + if (newlen >= maxsize-1) { + newmaxsize = 2*maxsize; + if (newlen >= newmaxsize -1) newmaxsize = newlen + 1; + nstr = get_pool(newmaxsize,newmaxsize); + strcpy(nstr,str); + put_pool(str,maxsize); + maxsize = newmaxsize; + str = nstr; + } + strcpy(str+len,newstr); + len += l; +} + +// --------------------------------------------------------------- +// String::add(char) +// +// Adds a single character to the current string +// --------------------------------------------------------------- + +void String::add(char nc) { + int newlen; + char *nstr = 0; + int newmaxsize; + + newlen = len+ 1; + if (newlen >= maxsize-1) { + newmaxsize = 2*maxsize; + if (newlen >= newmaxsize -1) newmaxsize = newlen + 1; + nstr = get_pool(newmaxsize,newmaxsize); + strcpy(nstr,str); + put_pool(str,maxsize); + maxsize = newmaxsize; + str = nstr; + } + str[len++] = nc; + str[len] = 0; +} + +// ----------------------------------------------------------------- +// String::insert(const char *newstr) +// +// Inserts a string into the front of a string. (Primarily used +// for documentation generation) +// ----------------------------------------------------------------- + +void String::insert(const char *newstr) { + int newlen; + char *nstr = 0; + int newmaxsize; + int i,l; + + l = strlen(newstr); + newlen = len + l + 1; + if (newlen >= maxsize-1) { + newmaxsize = 2*maxsize; + if (newlen >= newmaxsize -1) newmaxsize = newlen + 1; + nstr = get_pool(newmaxsize,newmaxsize); + strcpy(nstr,str); + put_pool(str,maxsize); + maxsize = newmaxsize; + str = nstr; + } + + /* Shift all of the characters over */ + + for (i = len -1; i >= 0; i--) { + str[i+l] = str[i]; + } + + /* Now insert the new string */ + + strncpy(str,newstr,l); + len += l; + str[len] = 0; + +} + +// ----------------------------------------------------------------- +// char *String::get() +// +// Get the current value of the string +// ----------------------------------------------------------------- + +char *String::get() const { + return str; +} + +// ----------------------------------------------------------------- +// String &operator<<(...) +// +// Shorthand for appending to the end of a string +// ----------------------------------------------------------------- + +String &operator<<(String &t,const char *s) { + t.add(s); + return t; +} + + +String &operator<<(String &t,const char s) { + t.add(s); + return t; +} + +String &operator<<(String &t,const int a) { + char temp[64]; + sprintf(temp,"%d",a); + t.add(temp); + return t; +} + +String &operator<<(String &t, String &s) { + t.add(s.get()); + return t; +} + +String &String::operator=(const char *s) { + int newlen; + + if (s) { + newlen = strlen(s); + if ((newlen >= maxsize) && (str)) { + put_pool(str,maxsize); + str = get_pool(newlen+1,maxsize); + maxsize = newlen+1; + } + strcpy(str,s); + len = newlen; + } else { + str[0] = 0; + len = 0; + } + return *this; +} + +// ----------------------------------------------------------------- +// String &operator>>(...) +// +// Shorthand for inserting into the beginning of a string +// ----------------------------------------------------------------- + +String &operator>>(const char *s, String &t) { + t.insert(s); + return t; +} + +String &operator>>(String &s, String &t) { + t.insert(s.get()); + return t; +} + +// ----------------------------------------------------------------- +// void String::untabify() +// +// Expand all tabs into spaces. This is useful for producing +// documentation and other things. +// ----------------------------------------------------------------- + +void String::untabify() { + char *s; + char *c; + int pos; + int i; + int oldmaxsize; + // Copy the current string representation + + s = str; + oldmaxsize = maxsize; + + // Reset the internal state of this string + + len = 0; + str = get_pool(maxsize,maxsize); + str[0]= 0; + + // Now walk down the old string and expand tabs. Tabs are usually place + // every 8 characters. + + pos = 0; + c = s; + while (*c) { + if (*c == '\n') { + pos = -1; + } + if (*c == '\t') { + // Expand the character + for (i = 0; i < (8 - (pos % 8)); i++) { + this->add(' '); + } + pos+=(8-(pos % 8)); + } else { + this->add(*c); + pos++; + } + c++; + } + + // Blow away the old string + put_pool(s,oldmaxsize); +} + + +// ----------------------------------------------------------------- +// void String::replace(const char *token, const char *rep) +// +// Search for tokens in a string and replace them with rep. +// This probably isn't the fastest implementation, but fortunately +// SWIG rarely calls this function. +// ----------------------------------------------------------------- + +void String::replace(const char *token, const char *rep) { + char *s, *c, *t; + int oldmaxsize = maxsize; + // Copy the current string representation + + s = str; + + // Now walk down the old string and search for tokens + + c = s; + t = strstr(c,token); + if (t) { + len = 0; + str = get_pool(maxsize,maxsize); + while (t) { + // Found a token in string s + // Dump characters into our string + char temp; + temp = *t; + *t = 0; + this->add(c); + c = t; + *t = temp; + + // Now dump the replacement string into place + + this->add(rep); + + // Jump over the token + + c+=strlen(token); + t = strstr(c,token); + } + // Attach rest of the string + if (*c) + this->add(c); + put_pool(s,oldmaxsize); + } +} + + +// ----------------------------------------------------------------- +// void String::replaceid(char *token, char *rep) +// +// Searches for valid identifiers matching token and replaces +// them with rep. Unlike replace() tokens must be a valid C +// identifier (surrounded by whitespace). +// ----------------------------------------------------------------- + +void String::replaceid(const char *token, const char *rep) { + char *s, *c, *t; + int whitespace, tokenlen; + int oldmaxsize = maxsize; + // Copy the current string representation + + s = str; + + // Reset the internal state of this string + + tokenlen = strlen(token); + + // Now walk down the old string and search for tokens + + c = s; + t = strstr(c,token); + if (t) { + len = 0; + str = get_pool(maxsize,maxsize); + while (t) { + // Found a token in string s + // Dump characters into our string + + whitespace = 1; + while (c != t) { + this->add(*c); + if (!(isalpha(*c) || (*c == '_') || (*c == '$'))) whitespace = 1; + else whitespace = 0; + c++; + } + + if (whitespace) { + // Check to see if there is whitespace afterwards + if ((!c[tokenlen]) || (!(isalnum(c[tokenlen]) || (c[tokenlen] == '_') || (c[tokenlen] == '$')))) { + this->add(rep); + } else { + this->add(token); + } + c+=tokenlen; + } else { + this->add(*c); + c++; + } + t = strstr(c,token); + } + + // Attach rest of the string + if (*c) + this->add(c); + + // Delete the old string + put_pool(s,oldmaxsize); + } +} + + +// ----------------------------------------------------------------- +// void String::strip() +// +// Intelligently strips whitespace from a string. Will not strip +// whitespace if it is between two characters that are part of a +// legal C identifier. For example 'unsigned int'. +// ----------------------------------------------------------------- + +void String::strip() { + char *s = str; // Old pointer value + char *c, lastchar = 0; + int whitespace = 0; + int oldmaxsize = maxsize; + + str = get_pool(maxsize,maxsize); // Get a new string. + len = 0; + + c = s; + while(*c) { + if (!isspace(*c)) { + // See if this character doesn't violate our whitespace rules + if (whitespace) { + if (isalnum(lastchar) || (lastchar == '_') || (lastchar == '$')) { + if (isalnum(*c) || (*c == '_') || (*c == '$')) + this->add(' '); + } + } + this->add(*c); + lastchar = *c; + whitespace = 0; + } else { + whitespace = 1; + } + c++; + } + put_pool(s,oldmaxsize); +} diff --git a/SWIG/Source/SWIG1.1/swig.h b/SWIG/Source/SWIG1.1/swig.h new file mode 100644 index 000000000..38b1cee09 --- /dev/null +++ b/SWIG/Source/SWIG1.1/swig.h @@ -0,0 +1,671 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ +/*********************************************************************** + * $Header$ + * + * swig.h + * + * This is the header file containing the main class definitions and + * declarations. Should be included in all extensions and code + * modules. + * + ***********************************************************************/ + +#include +#include +#include + +#include "swigver.h" + +/* Global variables. Needs to be cleaned up */ + +#ifdef MACSWIG +#define Status Swig_Status +#undef stderr +#define stderr swig_log +extern FILE *swig_log; +#endif + +extern FILE *f_runtime; // Runtime code +extern FILE *f_header; // Headers +extern FILE *f_wrappers; // Wrappers +extern FILE *f_init; // Initialization code +extern FILE *f_input; +extern char InitName[256]; +extern char LibDir[512]; // Library directory +extern char **InitNames; // List of other init functions +extern int Status; // Variable creation status +extern int TypeStrict; // Type checking strictness +extern int Verbose; +extern int yyparse(); +extern int line_number; +extern int start_line; +extern char *input_file; // Current input file +extern int CPlusPlus; // C++ mode +extern int ObjC; // Objective-C mode +extern int ObjCClass; // Objective-C style class +extern int AddMethods; // AddMethods mode +extern int NewObject; // NewObject mode +extern int Inline; // Inline mode +extern int NoInclude; // NoInclude flag +extern char *typemap_lang; // Current language name +extern int error_count; +extern char *copy_string(char *); +extern char output_dir[512]; // Output directory + +#define FatalError() if ((error_count++) > 20) { fprintf(stderr,"Confused by earlier errors. Bailing out\n"); SWIG_exit(1); } + +/* Miscellaneous stuff */ + +#define STAT_READONLY 1 +#define MAXSCOPE 16 + +// ----------------------------------------------------------------------- +// String class +// ----------------------------------------------------------------------- + +class String { +private: + int maxsize; // Max size of current string + void add(const char *newstr); // Function to add a new string + void add(char c); // Add a character + void insert(const char *newstr); + int len; + char *str; // String data +public: + String(); + String(const char *s); + ~String(); + char *get() const; + friend String& operator<<(String&,const char *s); + friend String& operator<<(String&,const int); + friend String& operator<<(String&,const char); + friend String& operator<<(String&,String&); + friend String& operator>>(const char *s, String&); + friend String& operator>>(String&,String&); + String& operator=(const char *); + operator char*() const { return str; } + void untabify(); + void replace(const char *token, const char *rep); + void replaceid(const char *id, const char *rep); + void strip(); +}; + +#define tab2 " " +#define tab4 " " +#define tab8 " " +#define br "\n" +#define endl "\n" +#define quote "\"" + +// ------------------------------------------------------------------- +// Hash table class +// ------------------------------------------------------------------- + +class Hash { +private: + struct Node { + Node(const char *k, void *obj, void (*d)(void *)) { + key = new char[strlen(k)+1]; + strcpy(key,k); + object = obj; + del_proc = d; + next = 0; + }; + ~Node() { + delete key; + if (del_proc) (*del_proc)(object); + }; + char *key; + void *object; + struct Node *next; + void (*del_proc)(void *); + }; + int h1(const char *key); // Hashing function + int hashsize; // Size of hash table + Node **hashtable; // Actual hash table + int index; // Current index (used by iterators) + Node *current; // Current item in hash table +public: + Hash(); + ~Hash(); + int add(const char *key, void *object); + int add(const char *key, void *object, void (*del)(void *)); + void *lookup(const char *key); + void remove(const char *key); + void *first(); + void *next(); + char *firstkey(); + char *nextkey(); +}; + +/************************************************************************ + * class DataType + * + * Defines the basic datatypes supported by the translator. + * + ************************************************************************/ + +#define T_INT 1 +#define T_SHORT 2 +#define T_LONG 3 +#define T_UINT 4 +#define T_USHORT 5 +#define T_ULONG 6 +#define T_UCHAR 7 +#define T_SCHAR 8 +#define T_BOOL 9 +#define T_DOUBLE 10 +#define T_FLOAT 11 +#define T_CHAR 12 +#define T_USER 13 +#define T_VOID 14 +#define T_SYMBOL 98 +#define T_ERROR 99 + +// These types are now obsolete, but defined for backwards compatibility + +#define T_SINT 90 +#define T_SSHORT 91 +#define T_SLONG 92 + +// Class for storing data types + +#define MAX_NAME 96 + +class DataType { +private: + static Hash *typedef_hash[MAXSCOPE]; + static int scope; +public: + int type; // SWIG Type code + char name[MAX_NAME]; // Name of type + char is_pointer; // Is this a pointer? + char implicit_ptr; // Implicit ptr + char is_reference; // A C++ reference type + char status; // Is this datatype read-only? + char *qualifier; // A qualifier string (ie. const). + char *arraystr; // String containing array part + int id; // type identifier (unique for every type). + DataType(); + DataType(DataType *); + DataType(int type); + ~DataType(); + void primitive(); // Turn a datatype into its primitive type + char *print_type(); // Return string containing datatype + char *print_full(); // Return string with full datatype + char *print_cast(); // Return string for type casting + char *print_mangle();// Return mangled version of type + char *print_real(char *local=0); // Print the real datatype (as far as we can determine) + char *print_arraycast(); // Prints an array cast + char *print_mangle_default(); // Default mangling scheme + + // Array query functions + int array_dimensions(); // Return number of array dimensions (if any) + char *get_dimension(int); // Return string containing a particular dimension + char *get_array(); // Returns the array string for a datatype + + // typedef support + + void typedef_add(char *name, int mode = 0); // Add this type to typedef list + void typedef_resolve(int level = 0); // See if this type has been typedef'd + void typedef_replace(); // Replace this type with it's original type +static int is_typedef(char *name); // See if this is a typedef + void typedef_updatestatus(int newstatus); // Change status of a typedef +static void init_typedef(void); // Initialize typedef manager +static void merge_scope(Hash *h); // Functions for managing scoping of datatypes +static void new_scope(Hash *h = 0); +static Hash *collapse_scope(char *); + int check_defined(); // Check to see if type is defined by a typedef. + void remember(); +}; + +#define STAT_REPLACETYPE 2 + +/************************************************************************ + * class Parm + * + * Structure for holding information about function parameters + * + * CALL_VALUE --> Call by value even though function parameter + * is a pointer. + * ex : foo(&_arg0); + * CALL_REF --> Call by reference even though function parameter + * is by value + * ex : foo(*_arg0); + * + ************************************************************************/ + +#define CALL_VALUE 0x01 +#define CALL_REFERENCE 0x02 +#define CALL_OUTPUT 0x04 + +struct Parm { + DataType *t; // Datatype of this parameter + int call_type; // Call type (value or reference or value) + char *name; // Name of parameter (optional) + char *defvalue; // Default value (as a string) + int ignore; // Ignore flag + char *objc_separator; // Parameter separator for Objective-C + Parm(DataType *type, char *n); + Parm(Parm *p); + ~Parm(); +}; + +// ------------------------------------------------------------- +// class ParmList +// +// This class is used for manipulating parameter lists in +// function and type declarations. +// ------------------------------------------------------------- + +#define MAXPARMS 16 + +class ParmList { +private: + int maxparms; // Max parms possible in current list + Parm **parms; // Pointer to parms array + void moreparms(); // Increase number of stored parms + int current_parm; // Internal state for get_first,get_next +public: + int nparms; // Number of parms in list + void append(Parm *p); // Append a parameter to the end + void insert(Parm *p, int pos); // Insert a parameter into the list + void del(int pos); // Delete a parameter at position pos + int numopt(); // Get number of optional arguments + int numarg(); // Get number of active arguments + Parm *get(int pos); // Get the parameter at position pos + Parm &operator[](int); // An alias for get(). + ParmList(); + ParmList(ParmList *l); + ~ParmList(); + + // Keep this for backwards compatibility + + Parm *get_first(); // Get first parameter from list + Parm *get_next(); // Get next parameter from list + void print_types(FILE *f); // Print list of datatypes + void print_types(String &f); // Generate list of datatypes. + void print_args(FILE *f); // Print argument list + int check_defined(); // Checks to make sure the arguments are defined + void sub_parmnames(String &s); // Remaps real parameter names in code fragment +}; + +// Modes for different types of inheritance + +#define INHERIT_FUNC 0x1 +#define INHERIT_VAR 0x2 +#define INHERIT_CONST 0x4 +#define INHERIT_ALL (INHERIT_FUNC | INHERIT_VAR | INHERIT_CONST) + +struct Pragma { + Pragma() { next = 0; } + String filename; + int lineno; + String lang; + String name; + String value; + Pragma *next; +}; + +/************************************************************************ + * class language: + * + * This class defines the functions that need to be supported by the + * scripting language being used. The translator calls these virtual + * functions to output different types of code for different languages. + * + * By implementing this using virtual functions, hopefully it will be + * easy to support different types of scripting languages. + * + * The following functions are used : + * + * parse_args(argc, argv) + * Parse the arguments used by this language. + * + * parse() + * Entry function that starts parsing of a particular language + * + * create_function(fname, iname, rtype, parmlist) + * Creates a function wrappper. + * + * link_variable(vname, iname, type) + * Creates a link to a variable. + * + * declare_const(cname, type, value) + * Creates a constant (for #define). + * + * initialize(char *fn) + * Produces initialization code. + * + * headers() + * Produce code for headers + * + * close() + * Close up files + * + * usage_var(iname,type,string) + * Produces usage string for variable declaration. + * + * usage_func(iname,rttype, parmlist, string) + * Produces usage string for function declaration. + * + * usage_const(iname, type, value, string) + * Produces usage string for constants + * + * set_module(char *modname) + * Sets the name of the module (%module directive) + * + * set_init(char *initname) + * Sets name of initialization function (an alternative to set_module) + * add_native(char *name, char *funcname); + * Adds a native wrapper function to the initialize process + * + * type_mangle(DataType *t); + * Mangles the name of a datatype. + * --- C++ Functions --- + * + * These functions are optional additions to any of the target + * languages. SWIG handles inheritance, symbol tables, and other + * information. + * + * cpp_open_class(char *classname, char *rname) + * Open a new C++ class definition. + * cpp_close_class(char *) + * Close current C++ class + * cpp_member_func(char *name, char *rname, DataType *rt, ParmList *l) + * Create a C++ member function + * cpp_constructor(char *name, char *iname, ParmList *l) + * Create a C++ constructor. + * cpp_destructor(char *name, char *iname) + * Create a C++ destructor + * cpp_variable(char *name, char *iname, DataType *t) + * Create a C++ member data item. + * cpp_declare_const(char *name, char *iname, int type, char *value) + * Create a C++ constant. + * cpp_inherit(char *baseclass) + * Inherit data from baseclass. + * cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) + * A C++ static member function. + * cpp_static_var(char *name, char *iname, DataType *t) + * A C++ static member data variable. + * + *************************************************************************/ + +class Language { +public: + virtual void parse_args(int argc, char *argv[]) = 0; + virtual void parse() = 0; + virtual void create_function(char *, char *, DataType *, ParmList *) = 0; + virtual void link_variable(char *, char *, DataType *) = 0; + virtual void declare_const(char *, char *, DataType *, char *) = 0; + virtual void initialize(void) = 0; + virtual void headers(void) = 0; + virtual void close(void) = 0; + virtual void set_module(char *mod_name,char **mod_list) = 0; + virtual void set_init(char *init_name); + virtual void add_native(char *, char *); + virtual char *type_mangle(DataType *t) { + return t->print_mangle_default(); + } + virtual void add_typedef(DataType *t, char *name); + virtual void create_command(char *cname, char *iname); + + // + // C++ language extensions. + // You can redefine these, or use the defaults below + // + + virtual void cpp_member_func(char *name, char *iname, DataType *t, ParmList *l); + virtual void cpp_constructor(char *name, char *iname, ParmList *l); + virtual void cpp_destructor(char *name, char *newname); + virtual void cpp_open_class(char *name, char *rename, char *ctype, int strip); + virtual void cpp_close_class(); + virtual void cpp_cleanup(); + virtual void cpp_inherit(char **baseclass, int mode = INHERIT_ALL); + virtual void cpp_variable(char *name, char *iname, DataType *t); + virtual void cpp_static_func(char *name, char *iname, DataType *t, ParmList *l); + virtual void cpp_declare_const(char *name, char *iname, DataType *type, char *value); + virtual void cpp_static_var(char *name, char *iname, DataType *t); + virtual void cpp_pragma(Pragma *plist); + + // Pragma directive + + virtual void pragma(char *, char *, char *); + + // Declaration of a class, but not a full definition + + virtual void cpp_class_decl(char *, char *, char *); + + // Import directive + + virtual void import(char *filename); + +}; + +class Documentation; + +// -------------------------------------------------------------------- +// class DocEntry +// +// Base class for the documentation system. Basically everything is +// a documentation entry of some sort. Specific derived classes +// are created internally and shouldn't be accessed by third-party +// modules. +// -------------------------------------------------------------------- + +class DocEntry { +public: + char *name; // Name of the entry + String usage; // Short description (optional) + String cinfo; // Information about C interface (optional). + String text; // Supporting text (optional) + DocEntry *parent; // Parent of this entry (optional) + DocEntry *child; // Children of this entry (optional) + DocEntry *next; // Next entry (or sibling) + DocEntry *previous; // Previous entry + int counter; // Counter for section control + int is_separator; // Is this a separator entry? + int sorted; // Sorted? + int line_number; // Line number + int end_line; // Ending line number + int format; // Format this documentation entry + int print_info; // Print C information about this entry + char *file; // File + virtual ~DocEntry(); // Destructor (common to all subclasses) + + // Methods applicable to all documentation entries + + virtual void output(Documentation *d); + void add(DocEntry *de); // Add documentation entry to the list + void addchild(DocEntry *de); // Add documentation entry as a child + void sort_children(); // Sort all of the children + void remove(); // Remove this doc entry + void parse_args(int argc, char **argv); // Parse command line options + void style(char *name,char *value);// Change doc style. + static DocEntry *dead_entries; // Dead documentation entries +}; + +extern DocEntry *doc_entry; + +// Default DocEntry style parameters + +#define SWIGDEFAULT_SORT 0 +#define SWIGDEFAULT_FORMAT 1 +#define SWIGDEFAULT_INFO 1 + +// ---------------------------------------------------------------------- +// Documentation module base class +// +// This class defines methods that need to be implemented for a +// documentation module. +// +// title() - Print out a title entry +// newsection() - Start a new section (may be nested to form subsections) +// endsection() - End a section +// print_decl() - Print a standard declaration +// print_text() - Print standard text +// init() - Initialize the documentation module +// close() - Close documentation module +// ---------------------------------------------------------------------- + +class Documentation { +public: + virtual void parse_args(int argc, char **argv) = 0; + virtual void title(DocEntry *de) = 0; + virtual void newsection(DocEntry *de, int sectnum) = 0; + virtual void endsection() = 0; + virtual void print_decl(DocEntry *de) = 0; + virtual void print_text(DocEntry *de) = 0; + virtual void separator() = 0; + virtual void init(char *filename) = 0; + virtual void close(void) = 0; + virtual void style(char *name, char *value) = 0; +}; + +/* Emit functions */ + +extern void emit_extern_var(char *, DataType *, int, FILE *); +extern void emit_extern_func(char *, DataType *, ParmList *, int, FILE *); +extern int emit_args(DataType *, ParmList *, FILE *); + +extern void emit_func_call(char *, DataType *, ParmList *, FILE *); + +extern void emit_hex(FILE *); +extern void emit_set_get(char *, char *, DataType *); +extern void emit_banner(FILE *); +extern void emit_ptr_equivalence(FILE *); +extern int SWIG_main(int, char **, Language *, Documentation *); +extern void make_wrap_name(char *); + +// Some functions for emitting some C++ helper code + +extern void cplus_emit_member_func(char *classname, char *classtype, char *classrename, + char *mname, char *mrename, DataType *type, ParmList *l, + int mode); + +extern void cplus_emit_static_func(char *classname, char *classtype, char *classrename, + char *mname, char *mrename, DataType *type, ParmList *l, + int mode); + +extern void cplus_emit_destructor(char *classname, char *classtype, char *classrename, + char *name, char *iname, int mode); + +extern void cplus_emit_constructor(char *classname, char *classtype, char *classrename, + char *name, char *iname, ParmList *l, int mode); + +extern void cplus_emit_variable_get(char *classname, char *classtype, char *classrename, + char *name, char *iname, DataType *type, int mode); + +extern void cplus_emit_variable_set(char *classname, char *classtype, char *classrename, + char *name, char *iname, DataType *type, int mode); + +extern char *cplus_base_class(char *name); + +extern void cplus_support_doc(String &f); + +/* Function for building search directories */ + +extern void add_directory(char *dirname); +extern int insert_file(char *, FILE *); +extern int get_file(char *filename, String &str); +extern int checkout_file(char *filename, char *dest); +extern int checkin_file(char *dir, char *lang, char *source, char *dest); +extern int include_file(char *filename); + +/* Miscellaneous */ + +extern void check_options(); +extern void init_args(int argc, char **); +extern void mark_arg(int n); +extern void arg_error(); + +extern void library_add(char *name); +extern void library_insert(); + +// ----------------------------------------------------------------------- +// Class for Creating Wrapper Functions +// ----------------------------------------------------------------------- + +class WrapperFunction { +private: + Hash h; + Hash localh; +public: + String def; + String locals; + String code; + String init; + void print(FILE *f); + void print(String &f); + void add_local(char *type, char *name, char *defvalue = 0); + char *new_local(char *type, char *name, char *defvalue = 0); +static void del_type(void *obj); +}; + +extern int emit_args(DataType *, ParmList *, WrapperFunction &f); +extern void emit_func_call(char *, DataType *, ParmList *, WrapperFunction &f); +extern void SWIG_exit(int); + +// Symbol table management + +extern int add_symbol(char *, DataType *, char *); +extern void remove_symbol(char *); +extern int update_symbol(char *, DataType *, char *); +extern char *lookup_symvalue(char *); +extern DataType *lookup_symtype(char *); +extern int lookup_symbol(char *); + +// ----------------------------------------------------------------------- +// Typemap support +// ----------------------------------------------------------------------- + +extern void typemap_register(char *op, char *lang, DataType *type, char *pname, char *code, ParmList *l = 0); +extern void typemap_register(char *op, char *lang, char *type, char *pname, char *code,ParmList *l = 0); +extern void typemap_register_default(char *op, char *lang, int type, int ptr, char *arraystr, char *code, ParmList *l = 0); +extern char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source, char *target, + WrapperFunction *f = 0); +extern void typemap_clear(char *op, char *lang, DataType *type, char *pname); +extern void typemap_copy(char *op, char *lang, DataType *stype, char *sname, DataType *ttype, char *tname); +extern char *typemap_check(char *op, char *lang, DataType *type, char *pname); +extern void typemap_apply(DataType *tm_type, char *tmname, DataType *type, char *pname); +extern void typemap_clear_apply(DataType *type, char *pname); + + +// ----------------------------------------------------------------------- +// Code fragment support +// ----------------------------------------------------------------------- + +extern void fragment_register(char *op, char *lang, char *code); +extern char *fragment_lookup(char *op, char *lang, int age); +extern void fragment_clear(char *op, char *lang); + + +extern void emit_ptr_equivalence(WrapperFunction &); + +// ----------------------------------------------------------------------- +// Naming system +// ----------------------------------------------------------------------- + +#define AS_IS 1 + +extern void name_register(char *method, char *format); +extern int name_scope(int); +extern char *name_wrapper(char *fname, char *prefix, int suppress=0); +extern char *name_member(char *fname, char *classname, int suppress=0); +extern char *name_get(char *vname, int suppress=0); +extern char *name_set(char *vname, int suppress=0); +extern char *name_construct(char *classname, int suppress=0); +extern char *name_destroy(char *classname, int suppress=0); diff --git a/SWIG/Source/SWIG1.1/symbol.cxx b/SWIG/Source/SWIG1.1/symbol.cxx new file mode 100644 index 000000000..afc5784d2 --- /dev/null +++ b/SWIG/Source/SWIG1.1/symbol.cxx @@ -0,0 +1,196 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" + +/******************************************************************************* + * $Header$ + * + * File : symbol.cxx + * + * Symbol table management. + * + *******************************************************************************/ + +// ----------------------------------------------------------------------------- +// Symbol object +// ----------------------------------------------------------------------------- + +struct Symbol { + ~Symbol() { + if (name) delete name; + if (type) delete type; + if (value) delete value; + } + char *name; + DataType *type; // Optional datatype + char *value; // Optional value (for constant expressions) +}; + +static Hash SymHash; // SWIG Symbol table + +// ----------------------------------------------------------------------------- +// int add_symbol(char *name, DataType *type, char *value) +// +// Adds a symbol to the symbol table. Returns -1 if symbol is already in the +// table. +// +// Inputs : +// name = Symbol name +// type = Datatype (for constants). Optional. +// value = Value string. Optional. +// +// Output : 0 on success, -1 if symbol already exists. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int add_symbol(char *name, DataType *type, char *value) { + + Symbol *s; + int ret; + + s = new Symbol; + s->name = copy_string(name); + if (type) + s->type = new DataType(type); + else s->type = (DataType *) 0; + if (value) + s->value = copy_string(value); + else s->value = (char *) 0; + + // Add this to the symbol table + + ret = SymHash.add(s->name, s); + if (ret == -1) { + delete s; + } + return ret; +} + +// ----------------------------------------------------------------------------- +// int lookup_symbol(char *name) +// +// Checks to see if a symbol is in the symbol table. +// +// Inputs : name = Symbol name +// +// Output : 0 if not found, 1 if found. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int lookup_symbol(char *name) { + Symbol *s; + + s = (Symbol *) SymHash.lookup(name); + if (s) return 1; + else return 0; +} + +// ----------------------------------------------------------------------------- +// DataType *lookup_symtype(char *name) +// +// Returns the datatype of a symbol or NULL if not found. +// +// Inputs : name = Symbol name +// +// Output : Datatype of symbol, NULL if not found. +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +DataType *lookup_symtype(char *name) { + + Symbol *s; + + s = (Symbol *) SymHash.lookup(name); + if (s) return s->type; + else return (DataType *) 0; +} + +// ----------------------------------------------------------------------------- +// char *lookup_symvalue(char *name) +// +// Returns the value associate with a symbol. +// +// Inputs : name = Symbol name +// +// Output : Symbol value (or NULL if not present). +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +char *lookup_symvalue(char *name) { + + Symbol *s; + + s = (Symbol *) SymHash.lookup(name); + if (s) return s->value; + else return (char *) 0; +} + +// ----------------------------------------------------------------------------- +// int update_symbol(char *name, DataType *type, char *value) +// +// Updates a symbol (or create it) in the hash table. +// +// Inputs : +// name = Name of symbol +// type = Datatype of symbol (optional) +// value = Symbol value (optional) +// +// Output : 0 +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +int update_symbol(char *name, DataType *type, char *value) { + + Symbol *s; + + s = (Symbol *) SymHash.lookup(name); + if (s) { + if (s->type) delete s->type; + if (s->value) delete s->value; + if (type) + s->type = new DataType(type); + else + s->type = (DataType *) 0; + if (value) + s->value = copy_string(value); + else + s->value = (char *) 0; + return 0; + } else { + return add_symbol(name, type, value); + } +} + +// ----------------------------------------------------------------------------- +// void remove_symbol(char *name) +// +// Removes a symbol from the symbol table. +// +// Inputs : name = Symbol name. +// +// Output : None +// +// Side Effects : None +// ----------------------------------------------------------------------------- + +void remove_symbol(char *name) { + SymHash.remove(name); +} diff --git a/SWIG/Source/SWIG1.1/typemap.cxx b/SWIG/Source/SWIG1.1/typemap.cxx new file mode 100644 index 000000000..bd6db74dd --- /dev/null +++ b/SWIG/Source/SWIG1.1/typemap.cxx @@ -0,0 +1,1093 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "internal.h" + +#include + +// ------------------------------------------------------------------------ +// $Header$ +// +// typemap.cxx +// +// This file provides universal support for typemaps. Typemaps are created +// using the following SWIG command in an interface file: +// +// %typemap(lang,operation) type { code } Make a new typemap +// %typemap(lang,operation) type; Clears any previous typemap +// +// lang is an identifier indicating the target language. The typemap will +// simply be ignored if its for a different language. The code is the +// corresponding C code for the mapping. An example typemap might look +// like this : +// +// %typemap(tcl,get) double { +// $target = atof($source); +// } +// %typemap(tcl,set) double { +// sprintf($target,"%0.17f",$source); +// } +// +// The variables $target and $source should be used in any type-mappings. +// Additional local variables can be created, but this should be done +// by enclosing the entire code fragment in an extra set of braces. +// +// The C++ API to the type-mapper is as follows : +// +// void typemap_register(char *op, char *lang, DataType *type, char *pname, String &getcode, ParmList *args) +// char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source, char *target); +// void typemap_clear(char *op, char *lang, DataType *type, char *pname); +// +// The lookup functions return a character string corresponding to the type-mapping +// code or NULL if none exists. The string return will have the source and target +// strings substituted for the strings "$source" and "$target" in the type-mapping code. +// +// (2/19/97) This module has been extended somewhat to provide generic mappings +// of other parts of the code--most notably exceptions. +// +// void fragment_register(char *op, char *lang, String &code) +// char fragment_lookup(char *op, char *lang, int age); +// char fragment_clear(char *op, char *lang); +// +// ------------------------------------------------------------------------ + +// Structure for holding a typemap + +struct TypeMap { + char *lang; + DataType *type; + String code; + int first; + int last; + TypeMap *next; + TypeMap *previous; // Previously defined typemap (if any) + ParmList *args; // Local variables (if any) + + TypeMap(char *l, DataType *t, String &c, ParmList *p = 0) { + lang = copy_string(l); + type = new DataType(t); + code << c; + first = type_id; + last = INT_MAX; + next = 0; + previous = 0; + if (p) { + args = new ParmList(p); + } else { + args = 0; + } + } + TypeMap(char *l, DataType *t, char *c, ParmList *p = 0) { + lang = copy_string(l); + type = new DataType(t); + code << c; + first = type_id; + last = INT_MAX; + next = 0; + previous = 0; + if (p) { + args = new ParmList(p); + } else { + args = 0; + } + } + TypeMap(char *l, char *c) { + lang = copy_string(l); + type = 0; + code << c; + first = type_id; + last = INT_MAX; + next = 0; + previous = 0; + args = 0; + } + TypeMap(TypeMap *t) { + lang = copy_string(t->lang); + type = new DataType(t->type); + code << t->code; + first = type_id; + last = INT_MAX; + next = 0; + previous = t->previous; + if (args) { + args = new ParmList(args); + } else { + args = 0; + } + } +}; + +// Hash tables for storing type-mappings + +static Hash typemap_hash; + +// Structure for holding "applications of a typemap" + +struct TmMethod { + char *name; // Typemap name; + DataType *type; // Typemap type + TmMethod *next; // Next method + TmMethod(char *n, DataType *t, TmMethod *m = 0) { + if (n) name = copy_string(n); + else name = 0; + if (t) { + type = new DataType(t); + } else { + type = 0; + } + next = m; + } +}; + +// Hash table for storing applications of a datatype + +static Hash application_hash; + +// ------------------------------------------------------------------------ +// void typemap_apply(DataType *tm_type, char *tm_name, DataType *type, char *pname) +// +// Attempts to apply a typemap given by (tm_type,tm_name) to (type,pname) +// Called by the %apply directive. +// ------------------------------------------------------------------------ + +void typemap_apply(DataType *tm_type, char *tm_name, DataType *type, char *pname) { + TmMethod *m,*m1; + char temp[512]; + + // Form the application name + if (!pname) pname = ""; + sprintf(temp,"%s$%s",type->print_type(),pname); + + // See if there is a method already defined + + m = (TmMethod *) application_hash.lookup(temp); + + if (!m) { + m = new TmMethod(temp,type,0); + application_hash.add(temp,m); + } + + // Check to see if an array typemap has been applied to a non-array type + + if ((tm_type->arraystr) && (!type->arraystr)) { + fprintf(stderr,"%s:%d: Warning. Array typemap has been applied to a non-array type.\n", + input_file,line_number); + } + + // If both are arrays, make sure they have the same dimension + + if ((tm_type->arraystr) && (type->arraystr)) { + char s[128],*t; + if (tm_type->array_dimensions() != type->array_dimensions()) { + fprintf(stderr,"%s:%d: Warning. Array types have different number of dimensions.\n", + input_file,line_number); + } else { + for (int i = 0; i < tm_type->array_dimensions(); i++) { + strcpy(s,tm_type->get_dimension(i)); + t = type->get_dimension(i); + if (strcmp(s,"ANY") != 0) { + if (strcmp(s,t)) + fprintf(stderr,"%s:%d: Warning. Array typemap applied to an array of different size.\n", + input_file, line_number); + } + } + } + } + + // Add a new mapping corresponding to the typemap + + m1 = new TmMethod(tm_name,tm_type,m->next); + m->next = m1; + +} +// ------------------------------------------------------------------------ +// void typemap_clear_apply(DataType *type, char *pname) +// +// Clears the application of a typemap. +// Called by the %clear directive. +// ------------------------------------------------------------------------ + +void typemap_clear_apply(DataType *type, char *pname) { + char temp[512]; + if (!pname) pname = ""; + sprintf(temp,"%s$%s", type->print_type(), pname); + application_hash.remove(temp); +} + +// ------------------------------------------------------------------------ +// char *typemap_string(char *lang, DataType *type, char *pname, char *ary, char *suffix) +// +// Produces a character string corresponding to a lang, datatype, and +// method. This string is used as the key for our typemap hash table. +// ------------------------------------------------------------------------ + +static char *typemap_string(char *lang, DataType *type, char *pname, char *ary, char *suffix) { + static String str; + + int old_status; + old_status = type->status; + type->status = 0; + str = ""; + + if (ary) + str << lang << type->print_type() << pname << ary << suffix; + else + str << lang << type->print_type() << pname << suffix; + + type->status = old_status; + return str; +} + +// ------------------------------------------------------------------------ +// void typemap_register(char *op, char *lang, DataType *type, char *pname, +// char *getcode, ParmList *args) +// +// Register a new mapping with the type-mapper. +// ------------------------------------------------------------------------ + +void typemap_register(char *op, char *lang, DataType *type, char *pname, + char *getcode, ParmList *args) { + + char *key; + TypeMap *tm,*tm_old; + char temp[256]; + int is_default = 0; + + // printf("Registering : %s %s %s %s\n%s\n", op, lang, type->print_type(), pname, getcode); + + + tm = new TypeMap(lang,type,getcode,args); + // If this is a default typemap, downgrade the type! + + if (strcmp(pname,"SWIG_DEFAULT_TYPE") == 0) { + tm->type->primitive(); + is_default = 1; + } + + key = typemap_string(lang,tm->type,pname,tm->type->arraystr, op); + + // Get any previous setting of the typemap + + tm_old = (TypeMap *) typemap_hash.lookup(key); + + if (tm_old) { + + // Perform a chaining operation, but only if the last typemap is + // active. + + if (type_id < tm_old->last) { + sprintf(temp,"$%s",op); + tm->code.replace(temp,tm_old->code); + } + + // If found, we need to attach the old version to the new one + + tm->previous = tm_old; + tm->next = tm_old; + tm_old->last = type_id; + + // Remove the old one from the hash + + typemap_hash.remove(key); + } + + // Add new typemap to the hash table + typemap_hash.add(key,(void *) tm); + + // Now try to perform default chaining operation (if available) + // if (!is_default) { + // sprintf(temp,"$%s",op); + // if (strstr(tm->code,temp)) { + // tm->code.replace(temp,typemap_resolve_default(op,lang,type)); + // } + // } + + // Just a sanity check to make sure args look okay. + + if (args) { + Parm *p; + p = tm->args->get_first(); + while (p) { + if (p->name) { + // printf(" %s %s\n", p->t->print_type(),p->name); + } else { + fprintf(stderr,"%s:%d: Typemap error. Local variables must have a name\n", + input_file, line_number); + } + // If a call by reference thingy, fix that + if (p->call_type & CALL_REFERENCE) { + p->t->is_pointer--; + p->call_type = 0; + } + p = tm->args->get_next(); + } + } +} + +// ------------------------------------------------------------------------ +// void typemap_register(char *op, char *lang, char *type, char *pname, +// char *getcode, ParmList *args) +// +// Register a new mapping with the type-mapper. Special version that uses a +// string instead of a datatype. +// ------------------------------------------------------------------------ + +void typemap_register(char *op, char *lang, char *type, char *pname, + char *getcode, ParmList *args) { + DataType temp; + strcpy(temp.name,type); + temp.is_pointer = 0; + temp.type = T_USER; + typemap_register(op,lang,&temp,pname,getcode,args); +} + + +// ------------------------------------------------------------------------ +// void typemap_register_default(char *op, char *lang, int type, int ptr, char *arraystr, +// char *code, ParmList *args) +// +// Registers a default typemap with the system using numerical type codes. +// type is the numerical code, ptr is the level of indirection. +// ------------------------------------------------------------------------ + +void typemap_register_default(char *op, char *lang, int type, int ptr, char *arraystr, + char *code, ParmList *args) { + + DataType *t = new DataType(type); + + // Create a raw datatype from the arguments + + t->is_pointer = ptr; + t->arraystr = copy_string(arraystr); + + // Now, go register this as a default type + + typemap_register(op,lang,t,"SWIG_DEFAULT_TYPE",code,args); + delete t; +} + + +// ------------------------------------------------------------------------ +// static TypeMap *typemap_search(char *key, int id) +// +// An internal function for searching for a particular typemap given +// a key value and datatype id. +// +// Basically this checks the hash table and then checks the id against +// first and last values, looking for a match. This is to properly +// handle scoping problems. +// ------------------------------------------------------------------------ + +TypeMap *typemap_search(char *key, int id) { + + TypeMap *tm; + + tm = (TypeMap *) typemap_hash.lookup(key); + while (tm) { + if ((id >= tm->first) && (id < tm->last)) return tm; + else tm = tm->next; + } + return tm; +} + +// ------------------------------------------------------------------------ +// TypeMap *typemap_search_array(char *op, char *lang, DataType *type, char *pname, String &str) +// +// Performs a typemap lookup on an array type. This is abit complicated +// because we need to look for ANY tags specifying that any array dimension +// is valid. The resulting code will be placed in str with dimension variables +// substituted. +// ------------------------------------------------------------------------ + +TypeMap *typemap_search_array(char *op, char *lang, DataType *type, char *pname, String &str) { + char *origarr = type->arraystr; + char *key; + int ndim,i,j,k,n; + TypeMap *tm; + char temp[10]; + + if (!type->arraystr) return 0; + + // First check to see if exactly this array has been mapped + + key = typemap_string(lang,type,pname,type->arraystr,op); + tm = typemap_search(key,type->id); + + // Check for unnamed array of specific dimensions + if (!tm) { + key = typemap_string(lang,type,"",type->arraystr,op); + tm = typemap_search(key,type->id); + } + + if (!tm) { + // We're going to go search for matches with the ANY tag + String tempastr; + ndim = type->array_dimensions(); // Get number of dimensions + j = (1 << ndim) - 1; // Status bits + for (i = 0; i < (1 << ndim); i++) { + // Form an array string + tempastr = ""; + k = j; + for (n = 0; n < ndim; n++) { + if (k & 1) { + tempastr << "[" << type->get_dimension(n) << "]"; + } else { + tempastr << "[ANY]"; + } + k = k >> 1; + } + // printf("checking (%s) : %s\n",origarr,tempastr.get()); + type->arraystr = tempastr.get(); + key = typemap_string(lang,type,pname,type->arraystr,op); + tm = typemap_search(key,type->id); + if (!tm) { + key = typemap_string(lang,type,"",type->arraystr,op); + tm = typemap_search(key,type->id); + } + type->arraystr = origarr; + if (tm) break; + j--; + } + } + + if (tm) { + str << tm->code; + ndim = type->array_dimensions(); + for (i = 0; i < ndim; i++) { + sprintf(temp,"$dim%d",i); + str.replace(temp,type->get_dimension(i)); + } + } + return tm; +} + +// ------------------------------------------------------------------------ +// static typemap_locals(Datatype *t, char *pname, String &s, ParmList *l, WrapperFunction &f) +// +// Takes a string, a parameter list and a wrapper function argument and +// starts creating local variables. +// +// Substitutes locals in the string with actual values used. +// ------------------------------------------------------------------------ + +static void typemap_locals(DataType *t, char *pname, String &s, ParmList *l, WrapperFunction &f) { + Parm *p; + char *new_name; + + p = l->get_first(); + while (p) { + if (p->name) { + if (strlen(p->name) > 0) { + String str; + DataType *tt; + + // If the user gave us $type as the name of the local variable, we'll use + // the passed datatype instead + + if (strcmp(p->t->name,"$type")==0 || strcmp(p->t->name,"$basetype")==0) { + tt = t; + } else { + tt = p->t; + } + + // Have a real parameter here + if (tt->arraystr) { + tt->is_pointer--; + str << p->name << tt->arraystr; + } + else { + str << p->name; + } + + // Substitute parameter names + str.replace("$arg",pname); + if (strcmp(p->t->name,"$basetype")==0) { + // use $basetype + char temp_ip = tt->is_pointer; + char temp_ip1 = tt->implicit_ptr; + tt->is_pointer = 0; + tt->implicit_ptr = 0; + new_name = f.new_local(tt->print_type(),str); + tt->is_pointer = temp_ip; + tt->implicit_ptr = temp_ip1; + } + else + new_name = f.new_local(tt->print_full(),str); + + if (tt->arraystr) tt->is_pointer++; + // Substitute + s.replaceid(p->name,new_name); + } + } + p = l->get_next(); + } + // If the original datatype was an array. We're going to go through and substitute + // it's array dimensions + + if (t->arraystr) { + char temp[10]; + for (int i = 0; i < t->array_dimensions(); i++) { + sprintf(temp,"$dim%d",i); + f.locals.replace(temp,t->get_dimension(i)); + } + } + +} + +// ------------------------------------------------------------------------ +// char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source, +// char *target, WrapperFunction *f) +// +// Looks up a "get" function in the type-map and returns a character string +// containing the appropriate translation code. +// +// op is string code for type of mapping +// lang is the target language string +// type is the datatype +// pname is an optional parameter name +// source is a string with the source variable +// target is a string containing the target value +// f is a wrapper function object (optional) +// +// Returns NULL if no mapping is found. +// +// Typemaps follow a few rules regarding naming and C pointers by checking +// declarations in this order. +// +// 1. type name [] - A named array (most specific) +// 2. type name - Named argument +// 3. type [] - Type with array +// 4. type - Ordinary type +// +// Array checking is only made if the datatype actally has an array specifier +// +// Array checking uses a special token "ANY" that indicates that any +// dimension will match. Since we are passed a real datatype here, we +// need to hack this a special case. +// +// Array dimensions are substituted into the variables $dim1, $dim2,...,$dim9 +// ------------------------------------------------------------------------ + +static DataType *realtype; // This is a gross hack +static char *realname = 0; // Real parameter name + +char *typemap_lookup_internal(char *op, char *lang, DataType *type, char *pname, char *source, + char *target, WrapperFunction *f) { + static String str; + char *key = 0; + TypeMap *tm = 0; + + if (!lang) { + return 0; + } + + // First check for named array + str = ""; + tm = typemap_search_array(op,lang,type,pname,str); + + // Check for named argument + if (!tm) { + key = typemap_string(lang,type,pname,0,op); + tm = typemap_search(key,type->id); + if (tm) + str << tm->code; + } + + // Check for unnamed type + if (!tm) { + key = typemap_string(lang,type,"",0,op); + tm = typemap_search(key,type->id); + if (tm) + str << tm->code; + } + if (!tm) return 0; + + // Now perform character replacements + + str.replace("$source",source); + str.replace("$target",target); + str.replace("$type", realtype->print_type()); + if (realname) { + str.replace("$parmname", realname); + } else { + str.replace("$parmname",""); + } + // Print base type (without any pointers) + { + char temp_ip = realtype->is_pointer; + char temp_ip1 = realtype->implicit_ptr; + realtype->is_pointer = 0; + realtype->implicit_ptr = 0; + char *bt = realtype->print_type(); + if (bt[strlen(bt)-1] == ' ') + bt[strlen(bt)-1] = 0; + str.replace("$basetype",bt); + str.replace("$basemangle",realtype->print_mangle()); + realtype->is_pointer = temp_ip; + realtype->implicit_ptr = temp_ip1; + } + + str.replace("$mangle",realtype->print_mangle()); + + // If there were locals and a wrapper function, replace + if ((tm->args) && f) { + typemap_locals(realtype, pname, str,tm->args,*f); + } + + // If there were locals and no wrapper function, print a warning + if ((tm->args) && !f) { + if (!pname) pname = ""; + fprintf(stderr,"%s:%d: Warning. '%%typemap(%s,%s) %s %s' being applied with ignored locals.\n", + input_file, line_number, lang,op, type->print_type(), pname); + } + + // Return character string + + return str; +} + +// ---------------------------------------------------------- +// Real function call that takes care of application mappings +// ---------------------------------------------------------- + +char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source, + char *target, WrapperFunction *f) { + TmMethod *m; + char temp[512]; + char *result; + char *ppname; + char *tstr; + + realtype = type; // The other half of the gross hack + realname = pname; + + // Try to apply typemap right away + + result = typemap_lookup_internal(op,lang,type,pname,source,target,f); + + // If not found, try to pick up anything that might have been + // specified with %apply + + if ((!result) && (pname)) { + int drop_pointer = 0; + ppname = pname; + if (!ppname) ppname = ""; + + // The idea : We're going to cycle through applications and + // drop pointers off until we get a match. + + while (drop_pointer <= (type->is_pointer - type->implicit_ptr)) { + type->is_pointer -= drop_pointer; + tstr = type->print_type(); + sprintf(temp,"%s$%s",tstr,ppname); + // No mapping was found. See if the name has been mapped with %apply + m = (TmMethod *) application_hash.lookup(temp); + if (!m) { + sprintf(temp,"%s$",tstr); + m = (TmMethod *) application_hash.lookup(temp); + } + if (m) { + m = m->next; + while (m) { + char *oldary = 0; + static String newarray; + if (*(m->name)) ppname = m->name; + else ppname = pname; + m->type->is_pointer += drop_pointer; + + // Copy old array string (just in case) + + oldary = m->type->arraystr; + + // If the mapping type is an array and has the 'ANY' keyword, we + // have to play some magic + + if ((m->type->arraystr) && (type->arraystr)) { + // Build up the new array string + newarray = ""; + for (int n = 0; n < m->type->array_dimensions(); n++) { + char *d = m->type->get_dimension(n); + if (strcmp(d,"ANY") == 0) { + newarray << "[" << type->get_dimension(n) << "]"; + } else { + newarray << "[" << d << "]"; + } + } + m->type->arraystr = newarray.get(); + } else if (type->arraystr) { + // If an array string is available for the current datatype, + // make it available. + m->type->arraystr = type->arraystr; + } + result = typemap_lookup_internal(op,lang,m->type,ppname,source,target,f); + m->type->arraystr = oldary; + m->type->is_pointer -= drop_pointer; + if (result) { + type->is_pointer += drop_pointer; + return result; + } + m = m->next; + } + } + type->is_pointer += drop_pointer; + drop_pointer++; + } + } + // Still no idea, try to find a default typemap + + if (!result) { + DataType *t = new DataType(type); + t->primitive(); // Knock it down to its basic type + result = typemap_lookup_internal(op,lang,t,"SWIG_DEFAULT_TYPE",source,target,f); + if (result) { + delete t; + return result; + } + if ((t->type == T_USER) || (t->is_pointer)) { + if ((t->type == T_CHAR) && (t->is_pointer == 1)) return 0; + + // Still no result, go even more primitive + t->type = T_USER; + t->is_pointer = 1; + if (t->arraystr) delete [] t->arraystr; + t->arraystr = 0; + t->primitive(); + result = typemap_lookup_internal(op,lang,t,"SWIG_DEFAULT_TYPE",source,target,f); + } + delete t; + } + return result; +} + +// ---------------------------------------------------------------------------- +// char *typemap_check(char *op, char *lang, DataType *type, char *pname) +// +// Checks to see if there is a typemap. Returns typemap string if found, NULL +// if not. +// ---------------------------------------------------------------------------- + +char *typemap_check_internal(char *op, char *lang, DataType *type, char *pname) { + static String str; + char *key = 0; + TypeMap *tm = 0; + + if (!lang) { + return 0; + } + // First check for named array + str = ""; + tm = typemap_search_array(op,lang,type,pname,str); + + // First check for named array + // + // if (type->arraystr) { + // key = typemap_string(lang,type,pname,type->arraystr,op); + // tm = typemap_search(key,type->id); + // } + + // Check for named argument + if (!tm) { + key = typemap_string(lang,type,pname,0,op); + tm = typemap_search(key,type->id); + } + + // Check for unnamed array + if ((!tm) && (type->arraystr)) { + key = typemap_string(lang,type,"",type->arraystr,op); + tm = typemap_search(key,type->id); + } + + // Check for unname type + if (!tm) { + key = typemap_string(lang,type,"",0,op); + tm = typemap_search(key,type->id); + } + if (!tm) return 0; + + str = ""; + str << tm->code; + + // Return character string + + return str; +} + +// Function for checking with applications + +char *typemap_check(char *op, char *lang, DataType *type, char *pname) { + TmMethod *m; + char temp[512]; + char *result; + char *ppname; + char *tstr; + // Try to apply typemap right away + + result = typemap_check_internal(op,lang,type,pname); + + if (!result) { + int drop_pointer = 0; + ppname = pname; + if (!ppname) ppname = ""; + + // The idea : We're going to cycle through applications and + // drop pointers off until we get a match. + + while (drop_pointer <= (type->is_pointer - type->implicit_ptr)) { + type->is_pointer -= drop_pointer; + tstr = type->print_type(); + sprintf(temp,"%s$%s",tstr,ppname); + // No mapping was found. See if the name has been mapped with %apply + m = (TmMethod *) application_hash.lookup(temp); + if (!m) { + sprintf(temp,"%s$",tstr); + m = (TmMethod *) application_hash.lookup(temp); + } + if (m) { + m = m->next; + while (m) { + char *oldary = 0; + static String newarray; + if (*(m->name)) ppname = m->name; + else ppname = pname; + m->type->is_pointer += drop_pointer; + oldary = m->type->arraystr; + + // If the mapping type is an array and has the 'ANY' keyword, we + // have to play some magic + + if ((m->type->arraystr) && (type->arraystr)) { + // Build up the new array string + newarray = ""; + for (int n = 0; n < m->type->array_dimensions(); n++) { + char *d = m->type->get_dimension(n); + if (strcmp(d,"ANY") == 0) { + newarray << "[" << type->get_dimension(n) << "]"; + } else { + newarray << "[" << d << "]"; + } + } + oldary = m->type->arraystr; + m->type->arraystr = newarray.get(); + } else if (type->arraystr) { + m->type->arraystr = type->arraystr; + } + result = typemap_check_internal(op,lang,m->type,ppname); + m->type->arraystr = oldary; + m->type->is_pointer -= drop_pointer; + if (result) { + type->is_pointer += drop_pointer; + return result; + } + m = m->next; + } + } + type->is_pointer += drop_pointer; + drop_pointer++; + } + } + + // If still no result, might have a default typemap + if (!result) { + DataType *t = new DataType(type); + t->primitive(); // Knock it down to its basic type + result = typemap_check_internal(op,lang,t,"SWIG_DEFAULT_TYPE"); + if (result) { + delete t; + return result; + } + if ((t->type == T_USER) || (t->is_pointer)) { + if ((t->type == T_CHAR) && (t->is_pointer == 1)) return 0; + // Still no result, go even more primitive + t->type = T_USER; + t->is_pointer = 1; + if (t->arraystr) delete [] t->arraystr; + t->arraystr = 0; + t->primitive(); + result = typemap_check_internal(op,lang,t,"SWIG_DEFAULT_TYPE"); + } + delete t; + } + return result; +} + +// ------------------------------------------------------------------------ +// void typemap_clear(char *op, char *lang, DataType *type, char *pname) +// +// Clears any previous typemap. This works like a stack. Clearing a +// typemap returns to any previous typemap in force. If there is no +// previous map, then don't worry about it. +// ------------------------------------------------------------------------ + +void typemap_clear(char *op, char *lang, DataType *type, char *pname) { + + char *key; + TypeMap *tm; + + key = typemap_string(lang,type,pname,type->arraystr,op); + + // Look for any previous version, simply set the last id if + // applicable. + + tm = (TypeMap *) typemap_hash.lookup(key); + if (tm) { + if (tm->last > type_id) tm->last = type_id; + } +} + +// ------------------------------------------------------------------------ +// void typemap_copy(char *op, char *lang, DataType *stype, char *sname, +// DataType *ttype, char *tname) +// +// Copies the code associate with a typemap +// ------------------------------------------------------------------------ + +void typemap_copy(char *op, char *lang, DataType *stype, char *sname, + DataType *ttype, char *tname) { + + char *key; + TypeMap *tm, *tk, *tn; + + // Try to locate a previous typemap + + key = typemap_string(lang,stype,sname,stype->arraystr,op); + tm = typemap_search(key,stype->id); + if (!tm) return; + if (strcmp(ttype->name,"PREVIOUS") == 0) { + // Pop back up to the previous typemap (if any) + tk = tm->next; + if (tk) { + tn = new TypeMap(tk); // Make a copy of the previous typemap + tn->next = tm; // Set up symlinks + typemap_hash.remove(key); // Remove old hash entry + typemap_hash.add(key,(void *) tn); + } + } else { + typemap_register(op,lang,ttype,tname,tm->code,tm->args); + } +} + +// ------------------------------------------------------------------------ +// char *fragment_string(char *op, char *lang) +// +// Produces a character string corresponding to a language and method +// This string is used as the key for our typemap hash table. +// ------------------------------------------------------------------------ + +static char *fragment_string(char *op, char *lang) { + static String str; + + str = ""; + + str << "fragment:" << lang << op; + return str; +} + +// ------------------------------------------------------------------------ +// void fragment_register(char *op, char *lang, char *code) +// +// Register a code fragment with the type-mapper. +// ------------------------------------------------------------------------ + +void fragment_register(char *op, char *lang, char *code) { + + char *key; + TypeMap *tm,*tm_old; + char temp[256]; + + tm = new TypeMap(lang,code); + key = fragment_string(op,lang); + + // Get any previous setting of the typemap + + tm_old = (TypeMap *) typemap_hash.lookup(key); + if (tm_old) { + // If found, we need to attach the old version to the new one + + // Perform a chaining operation + + sprintf(temp,"$%s",op); + if (type_id < tm_old->last) + tm->code.replace(temp,tm_old->code); + + tm->next = tm_old; + tm_old->last = type_id; + + // Remove the old one from the hash + + typemap_hash.remove(key); + } + + // Perform a default chaining operation if needed (defaults to nothing) + sprintf(temp,"$%s",op); + tm->code.replace(temp,""); + + // Add new typemap to the hash table + typemap_hash.add(key,(void *) tm); + +} + + +// ------------------------------------------------------------------------ +// char *fragment_lookup(char *op, char *lang, int age) +// +// op is string code for type of mapping +// lang is the target language string +// age is age of fragment. +// +// Returns NULL if no mapping is found. +// +// ------------------------------------------------------------------------ + +char *fragment_lookup(char *op, char *lang, int age) { + static String str; + char *key = 0; + TypeMap *tm = 0; + + if (!lang) { + return 0; + } + + str = ""; + key = fragment_string(op,lang); + tm = typemap_search(key,age); + + if (!tm) return 0; + + str << tm->code; + return str; +} + +// ------------------------------------------------------------------------ +// void fragment_clear(char *op, char *lang) +// +// Clears any previous fragment definition. Is a stack operation--will +// restore any previously declared typemap. +// ------------------------------------------------------------------------ + +void fragment_clear(char *op, char *lang) { + + char *key; + TypeMap *tm; + + key = fragment_string(op,lang); + + // Look for any previous version, simply set the last id if + // applicable. + + tm = (TypeMap *) typemap_hash.lookup(key); + if (tm) { + if (tm->last > type_id) tm->last = type_id; + } +} diff --git a/SWIG/Source/SWIG1.1/types.cxx b/SWIG/Source/SWIG1.1/types.cxx new file mode 100644 index 000000000..e517393c4 --- /dev/null +++ b/SWIG/Source/SWIG1.1/types.cxx @@ -0,0 +1,1148 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +/*********************************************************************** + * $Header$ + * + * types.cxx + * + * This file contains functions for dealing with datatypes. This + * is a combination of the file typedef.cc (now obsolete) and functions + * that used to be in the swig.h header. + * + ***********************************************************************/ + +#include "internal.h" + +// ------------------------------------------------------------------- +// class DataType member functions. +// ------------------------------------------------------------------- + +DataType::DataType() { + type = 1; + name[0] = 0; + is_pointer = 0; + implicit_ptr = 0; + qualifier = 0; + is_reference = 0; + status = 0; + arraystr = 0; + id = type_id++; +} + +// Create a data type only from the type code (used to form constants) + +DataType::DataType(int t) { + switch(t) { + case T_BOOL: + strcpy(name,"bool"); + break; + case T_INT: case T_SINT: + strcpy(name,"int"); + break; + case T_UINT: + strcpy(name,"unsigned int"); + break; + case T_SHORT: case T_SSHORT: + strcpy(name,"short"); + break; + case T_USHORT: + strcpy(name,"unsigned short"); + break; + case T_LONG: case T_SLONG: + strcpy(name,"long"); + break; + case T_ULONG: + strcpy(name,"unsigned long"); + break; + case T_FLOAT: + strcpy(name, "float"); + break; + case T_DOUBLE: + strcpy(name, "double"); + break; + case T_CHAR: case T_SCHAR: + strcpy(name, "char"); + break; + case T_UCHAR: + strcpy(name,"unsigned char"); + break; + case T_VOID: + strcpy(name,"void"); + break; + case T_USER: + strcpy(name,"USER"); + break; + default : + strcpy(name,"UNKNOWN"); + break; + } + type = t; + is_pointer = 0; + implicit_ptr = 0; + qualifier = 0; + is_reference = 0; + status = 0; + arraystr = 0; + id = type_id++; +} + +DataType::DataType(DataType *t) { + type = t->type; + strcpy(name,t->name); + is_pointer = t->is_pointer; + implicit_ptr = t->implicit_ptr; + qualifier = copy_string(t->qualifier); + is_reference = t->is_reference; + status = t->status; + arraystr = copy_string(t->arraystr); + id = t->id; +} + +DataType::~DataType() { + if (qualifier) delete qualifier; + if (arraystr) delete arraystr; +} + +// -------------------------------------------------------------------- +// DataType::primitive() +// +// Turns a datatype into its bare-bones primitive type. Rarely used, +// but sometimes used for typemaps. Permanently alters the datatype! +// -------------------------------------------------------------------- + +void DataType::primitive() { + switch(type) { + case T_BOOL: + strcpy(name,"bool"); + break; + case T_INT: case T_SINT: + strcpy(name,"int"); + break; + case T_SHORT: case T_SSHORT: + strcpy(name,"short"); + break; + case T_LONG: case T_SLONG: + strcpy(name,"long"); + break; + case T_CHAR: + strcpy(name,"char"); + break; + case T_SCHAR: + strcpy(name,"signed char"); + break; + case T_UINT: + strcpy(name,"unsigned int"); + break; + case T_USHORT: + strcpy(name,"unsigned short"); + break; + case T_ULONG: + strcpy(name,"unsigned long"); + break; + case T_UCHAR: + strcpy(name,"unsigned char"); + break; + case T_FLOAT: + strcpy(name,"float"); + break; + case T_DOUBLE: + strcpy(name,"double"); + break; + case T_VOID: + strcpy(name,"void"); + break; + case T_USER: + strcpy(name,"USER"); + break; + default: + strcpy(name,"UNKNOWN"); + break; + } + // if (is_pointer) { + // if (!((is_pointer == 1) && (type == T_CHAR))) { + // is_pointer = 1; + // strcpy(name,"POINTER"); + // } + // } + + implicit_ptr = 0; // Gets rid of typedef'd pointers + + // Ditch qualifiers (const, volatile, etc...) + + if (qualifier) { + delete qualifier; + qualifier = 0; + } + qualifier = 0; + status = 0; +} + +// -------------------------------------------------------------------- +// char *print_type() +// +// Print the datatype, but without qualifiers (ie. const, volatile) +// Returns a string containing the result. +// +// If a datatype is marked as an implicit ptr it means that is_pointer +// is at least one, but we don't print '*'. +// +// If the type status is STAT_REPLACETYPE, it means that we can't +// use this type as a valid type. We'll substitute it's old name in. +// -------------------------------------------------------------------- + +char *DataType::print_type() { + static String result[8]; + static int ri = 0; + + DataType *t = this; + + if (status & STAT_REPLACETYPE) { + t = new DataType(this); + t->typedef_replace(); // Upgrade type + } + + ri = ri % 8; + result[ri] = ""; + result[ri] << t->name << " "; + for (int i = 0; i < (t->is_pointer-t->implicit_ptr); i++) + result[ri] << '*'; + + if (status & STAT_REPLACETYPE) { + delete t; + }; + + return result[ri++].get(); + +} + +// -------------------------------------------------------------------- +// char *print_full() +// +// Prints full type, with qualifiers. +// -------------------------------------------------------------------- + +char *DataType::print_full() { + static String result[8]; + static int ri = 0; + + ri = ri % 8; + result[ri] = ""; + if (qualifier) + result[ri] << qualifier << " " << print_type(); + else + result[ri] << print_type(); + + return result[ri++].get(); + +} + +// -------------------------------------------------------------------- +// char *print_real() +// +// Prints real type, with qualifiers and arrays if necessary. +// -------------------------------------------------------------------- + +char *DataType::print_real(char *local) { + static String result[8]; + static int ri = 0; + int oldstatus; + + oldstatus = status; + status = status & (~STAT_REPLACETYPE); + ri = ri % 8; + result[ri] = ""; + if (arraystr) is_pointer--; + result[ri] << print_full(); + if (local) result[ri] << local; + if (arraystr) { + result[ri] << arraystr; + is_pointer++; + } + status = oldstatus; + return result[ri++].get(); +} + +// -------------------------------------------------------------------- +// char *print_cast() +// +// Prints a cast. (Basically just a type but with parens added). +// -------------------------------------------------------------------- + +char *DataType::print_cast() { + static String result[8]; + static int ri = 0; + + ri = ri % 8; + result[ri] = ""; + result[ri] << "(" << print_type() << ")"; + return result[ri++].get(); + +} + +// -------------------------------------------------------------------- +// char *print_arraycast() +// +// Prints a cast, but for array datatypes. Super ugly, but necessary +// for multidimensional arrays. +// -------------------------------------------------------------------- + +char *DataType::print_arraycast() { + static String result[8]; + static int ri = 0; + int ndim; + char *c; + DataType *t; + + t = this; + if (status & STAT_REPLACETYPE) { + t = new DataType(this); + t->typedef_replace(); // Upgrade type + } + + ri = ri % 8; + result[ri] = ""; + + if (t->arraystr) { + ndim = 0; + c = t->arraystr; + while (*c) { + if (*c == '[') ndim++; + c++; + } + if (ndim > 1) { + // a Multidimensional array. Provide a special cast for it + int oldstatus = status; + t->status = t->status & (~STAT_REPLACETYPE); + t->is_pointer--; + result[ri] << "(" << t->print_type(); + t->is_pointer++; + t->status = oldstatus; + result[ri] << " (*)"; + c = t->arraystr; + while (*c) { + if (*c == ']') break; + c++; + } + if (*c) c++; + result[ri] << c << ")"; + } + } + if (status & STAT_REPLACETYPE) { + delete t; + } + return result[ri++].get(); +} + +// -------------------------------------------------------------------- +// char *print_mangle_default() +// +// Prints a mangled version of this datatype. Used for run-time type +// checking in order to print out a "language friendly" version (ie. no +// spaces and no weird characters). +// -------------------------------------------------------------------- + +char *DataType::print_mangle_default() { + static String result[8]; + static int ri = 0; + int i; + char *c; + + ri = ri % 8; + result[ri] = ""; + c = name; + + result[ri] << '_'; + + if ((strncmp(c,"struct ",7) == 0) || (strncmp(c,"class ",6) == 0) || (strncmp(c,"union ",6) == 0)) { + c = strchr(c,' ') + 1; + } + // if (d) c = d+1; + for (; *c; c++) { + if ((*c == ' ') || (*c == ':')) result[ri] << '_'; + else result[ri] << *c; + } + if ((is_pointer-implicit_ptr)) result[ri] << '_'; + for (i = 0; i < (is_pointer-implicit_ptr); i++) + result[ri] << 'p'; + + return result[ri++].get(); +} + +// This is kind of ugly but needed for each language to support a +// custom name mangling mechanism. (ie. Perl5). + +char *DataType::print_mangle() { + // Call into target language for name mangling. + return lang->type_mangle(this); +} + +// -------------------------------------------------------------------- +// int DataType::array_dimensions() +// +// Returns the number of dimensions in an array or 0 if not an array. +// -------------------------------------------------------------------- +int DataType::array_dimensions() { + char *c; + int ndim = 0; + + if (!arraystr) return 0; + c = arraystr; + while (*c) { + if (*c == '[') { + ndim++; + } + c++; + } + return ndim; +} + +// -------------------------------------------------------------------- +// char *DataType::get_dimension(int n) +// +// Returns a string containing the value specified for dimension n. +// -------------------------------------------------------------------- + +char *DataType::get_dimension(int n) { + static String dim; + char *c; + + dim = ""; + if (n >= array_dimensions()) return dim; + + // Attemp to locate the right dimension + + c = arraystr; + while ((*c) && (n >= 0)) { + if (*c == '[') n--; + c++; + } + + // c is now at start of array dimension + if (*c) { + while ((*c) && (*c != ']')) { + dim << *c; + c++; + } + } + return dim; +} + +// -------------------------------------------------------------------- +// char *DataType::get_array() +// +// Returns the array string for a datatype. +// -------------------------------------------------------------------- + +char *DataType::get_array() { + return arraystr; +} + +// -------------------------------------------------------------------- +// typedef support. This needs to be scoped. +// -------------------------------------------------------------------- + +Hash *DataType::typedef_hash[MAXSCOPE]; +int DataType::scope = 0; // Current scope + +static Hash undefined_types; // Hash table containing undefined datatypes. + +// ----------------------------------------------------------------------------- +// int DataType::check_defined() +// +// Checks to see if a datatype is defined. If not, returns -1 and puts an entry +// into an internal hash table +// ----------------------------------------------------------------------------- + +int DataType::check_defined() { + if (type == T_USER) { + + // Type might be in typedef hash. Check for that + int s = scope; + while (s >= 0) { + if (typedef_hash[s]->lookup(name)) return 0; + s--; + } + + // Nope. Add as an undefined type and continue. + + char *st; + st = copy_string(name); + undefined_types.add(st,st); + return -1; + } + return 0; +} + +// ----------------------------------------------------------------------------- +// void DataType::init_typedef() +// +// Inputs : None +// +// Output : None +// +// Side Effects : Initializes the typedef hash tables +// ----------------------------------------------------------------------------- + +void DataType::init_typedef() { + int i; + for (i = 0; i < MAXSCOPE; i++) + typedef_hash[i] = 0; + scope = 0; + // Create a new hash + typedef_hash[scope] = new Hash; +} + +// -------------------------------------------------------------------- +// void DataType::typedef_add(char *typename, int mode = 0) +// +// Adds this datatype to the typedef hash table. mode is an optional +// flag that can be used to only add the symbol as a typedef, but not +// generate any support code for the SWIG typechecker. This is used +// for some of the more obscure datatypes like function pointers, +// arrays, and enums. +// -------------------------------------------------------------------- + +void DataType::typedef_add(char *tname, int mode) { + String name1,name2; + DataType *nt, t1; + void typeeq_addtypedef(char *name, char *eqname, DataType *); + + // Check to see if this typedef already defined + // We only check in the local scope. C++ classes may make typedefs + // that shadow global ones. + + if (typedef_hash[scope]->lookup(tname)) { + fprintf(stderr,"%s : Line %d. Warning. Datatype %s already defined (2nd definition ignored).\n", + input_file, line_number, tname); + return; + } + + // Make a new datatype that we will place in our hash table + + nt = new DataType(this); + nt->implicit_ptr = (is_pointer-implicit_ptr); // Record if mapped type is a pointer + nt->is_pointer = (is_pointer-implicit_ptr); // Adjust pointer value to be correct + nt->typedef_resolve(); // Resolve any other mappings of this type + // strcpy(nt->name,tname); // Copy over the new name + + // Add this type to our hash table + typedef_hash[scope]->add(tname,(void *) nt); + + // Now add this type mapping to our type-equivalence table + + if (mode == 0) { + if ((type != T_VOID) && (strcmp(name,tname) != 0)) { + strcpy(t1.name,tname); + name2 << t1.print_mangle(); + name1 << print_mangle(); + typeeq_addtypedef(name1,name2,&t1); + typeeq_addtypedef(name2,name1,this); + } + } + // Call into the target language with this typedef + lang->add_typedef(this,tname); +} + + +// -------------------------------------------------------------------- +// void DataType::typedef_resolve(int level = 0) +// +// Checks to see if this datatype is in the typedef hash and +// resolves it if necessary. This will check all of the typedef +// hash tables we know about. +// +// level is an optional parameter that determines which scope to use. +// Usually this is only used with a bare :: operator in a datatype. +// +// The const headache : +// +// Normally SWIG will fail if a const variable is used in a typedef +// like this : +// +// typedef const char *String; +// +// This is because future occurrences of "String" will be treated like +// a char *, but without regard to the "constness". To work around +// this problem. The resolve() method checks to see if these original +// data type is const. If so, we'll substitute the name of the original +// datatype instead. Got it? Whew. In a nutshell, this means that +// all future occurrences of "String" will really be "const char *". +// -------------------------------------------------------------------- + +void DataType::typedef_resolve(int level) { + + DataType *td; + int s = scope - level; + + while (s >= 0) { + if ((td = (DataType *) typedef_hash[s]->lookup(name))) { + type = td->type; + is_pointer += td->is_pointer; + implicit_ptr += td->implicit_ptr; + status = status | td->status; + + // Check for constness, and replace type name if necessary + + if (td->qualifier) { + if (strcmp(td->qualifier,"const") == 0) { + strcpy(name,td->name); + qualifier = copy_string(td->qualifier); + implicit_ptr -= td->implicit_ptr; + } + } + return; + } + s--; + } + // Not found, do nothing + return; +} + +// -------------------------------------------------------------------- +// void DataType::typedef_replace() +// +// Checks to see if this datatype is in the typedef hash and +// replaces it with the hash entry. Only applies to current scope. +// -------------------------------------------------------------------- + +void DataType::typedef_replace () { + DataType *td; + String temp; + + if ((td = (DataType *) typedef_hash[scope]->lookup(name))) { + type = td->type; + is_pointer = td->is_pointer; + implicit_ptr -= td->implicit_ptr; + strcpy(name, td->name); + if (td->arraystr) { + if (arraystr) { + temp << arraystr; + delete arraystr; + } + temp << td->arraystr; + arraystr = copy_string(temp); + } + } + // Not found, do nothing + return; +} + +// --------------------------------------------------------------- +// int DataType::is_typedef(char *t) +// +// Checks to see whether t is the name of a datatype we know +// about. Returns 1 if there's a match, 0 otherwise +// --------------------------------------------------------------- + +int DataType::is_typedef(char *t) { + int s = scope; + while (s >= 0) { + if (typedef_hash[s]->lookup(t)) return 1; + s--; + } + return 0; +} + +// --------------------------------------------------------------- +// void DataType::typedef_updatestatus(int newstatus) +// +// Checks to see if this datatype is in the hash table. If +// so, we'll update its status. This is sometimes used with +// typemap handling. Only applies to current scope. +// --------------------------------------------------------------- + +void DataType::typedef_updatestatus(int newstatus) { + + DataType *t; + if ((t = (DataType *) typedef_hash[scope]->lookup(name))) { + t->status = newstatus; + } +} + + +// ----------------------------------------------------------------------------- +// void DataType::merge_scope(Hash *h) +// +// Copies all of the entries in scope h into the current scope. This is +// primarily done with C++ inheritance. +// +// Inputs : Hash table h. +// +// Output : None +// +// Side Effects : Copies all of the entries in h to current scope. +// ----------------------------------------------------------------------------- + +void DataType::merge_scope(Hash *h) { + char *key; + DataType *t, *nt; + + if (h) { + // Copy all of the entries in the given hash table to this new one + key = h->firstkey(); + while (key) { + // printf("%s\n", key); + t = (DataType *) h->lookup(key); + nt = new DataType(t); + typedef_hash[scope]->add(key,(void *) nt); + key = h->nextkey(); + } + } +} + +// ----------------------------------------------------------------------------- +// void DataType::new_scope(Hash *h = 0) +// +// Creates a new scope for handling typedefs. This is used in C++ handling +// to create typedef local to a class definition. +// +// Inputs : h = Optional hash table scope (Used for C++ inheritance). +// +// Output : None +// +// Side Effects : Creates a new hash table and increments the scope counter +// ----------------------------------------------------------------------------- + +void DataType::new_scope(Hash *h) { + scope++; + typedef_hash[scope] = new Hash; + + if (h) { + merge_scope(h); + } +} + +// ----------------------------------------------------------------------------- +// Hash *DataType::collapse_scope(char *prefix) +// +// Collapses the current scope into the previous one, but applies a prefix to +// all of the datatypes. This is done in order to properly handle C++ stuff. +// For example : +// +// class Foo { +// ... +// typedef double Real; +// } +// +// will have a type mapping of "double --> Real" within the class itself. +// When we collapse the scope, this mapping will become "double --> Foo::Real" +// +// Inputs : None +// +// Output : None +// +// Side Effects : Returns the hash table corresponding to the current scope +// ----------------------------------------------------------------------------- + +Hash *DataType::collapse_scope(char *prefix) { + DataType *t,*nt; + char *key; + char *temp; + Hash *h; + + if (scope > 0) { + if (prefix) { + key = typedef_hash[scope]->firstkey(); + while (key) { + t = (DataType *) typedef_hash[scope]->lookup(key); + nt = new DataType(t); + temp = new char[strlen(prefix)+strlen(key)+3]; + sprintf(temp,"%s::%s",prefix,key); + // printf("creating %s\n", temp); + typedef_hash[scope-1]->add(temp,(void *) nt); + delete temp; + key = typedef_hash[scope]->nextkey(); + } + } + h = typedef_hash[scope]; + typedef_hash[scope] = 0; + scope--; + return h; + } + return (Hash *) 0; +} + +// ------------------------------------------------------------- +// Class equivalency lists +// +// These are used to keep track of which datatypes are equivalent. +// This information can be dumped in tabular form upon completion +// for use in the pointer type checker. +// +// cast is an extension needed to properly handle multiple inheritance +// -------------------------------------------------------------- + +struct EqEntry { + char *name; + char *cast; + DataType *type; + EqEntry *next; +}; + +static Hash typeeq_hash; +static int te_init = 0; + +void typeeq_init() { + void typeeq_standard(); + te_init = 1; + typeeq_standard(); +} + + +// -------------------------------------------------------------- +// typeeq_add(char *name, char *eqname, char *cast) +// +// Adds a new name to the type-equivalence tables. +// Creates a new entry if it doesn't exit. +// +// Cast is an optional name for a pointer casting function. +// -------------------------------------------------------------- + +void typeeq_add(char *name, char *eqname, char *cast = 0, DataType *type = 0) { + EqEntry *e1,*e2; + + if (!te_init) typeeq_init(); + + if (strcmp(name,eqname) == 0) return; // If they're the same, forget it. + + // Search for "name" entry in the hash table + + e1 = (EqEntry *) typeeq_hash.lookup(name); + + if (!e1) { + // Create a new entry + e1 = new EqEntry; + e1->name = copy_string(name); + e1->next = 0; + e1->cast = 0; + // Add it to the hash table + typeeq_hash.add(name,(void *) e1); + } + + // Add new type to the list + // We'll first check to see if it's already been added + + e2 = e1->next; + while (e2) { + if (strcmp(e2->name, eqname) == 0) { + if (cast) + e2->cast = copy_string(cast); + return; + } + e2 = e2->next; + } + + e2 = new EqEntry; + e2->name = copy_string(eqname); + e2->cast = copy_string(cast); + if (type) + e2->type = new DataType(type); + else + e2->type = 0; + e2->next = e1->next; // Add onto the linked list for name + e1->next = e2; + +} + +// -------------------------------------------------------------- +// typeeq_addtypedef(char *name, char *eqname, DataType *t) +// +// Adds a new typedef declaration to the equivelency list. +// -------------------------------------------------------------- + +void typeeq_addtypedef(char *name, char *eqname, DataType *t) { + EqEntry *e1,*e2; + + if (!te_init) typeeq_init(); + + if (!t) { + t = new DataType(T_USER); + strcpy(t->name, eqname); + } + + // printf("addtypedef: %s : %s : %s\n", name, eqname, t->print_type()); + + // First we're going to add the equivalence, no matter what + + typeeq_add(name,eqname,0,t); + + // Now find the hash entry + + e1 = (EqEntry *) typeeq_hash.lookup(name); + if (!e1) return; + + // Walk down the list and make other equivalences + + e2 = e1->next; + while (e2) { + if (strcmp(e2->name, eqname) != 0) { + typeeq_add(e2->name, eqname,e2->cast,t); + typeeq_add(eqname, e2->name,e2->cast,e2->type); + } + e2 = e2->next; + } +} + +// ---------------------------------------------------------------- +// void emit_ptr_equivalence(FILE *f) +// +// Dump out the pointer equivalence table to file. +// +// Changed to register datatypes with the type checker in order +// to support proper type-casting (needed for multiple inheritance) +// ---------------------------------------------------------------- + +void emit_ptr_equivalence(FILE *f) { + + EqEntry *e1,*e2; + void typeeq_standard(); + String ttable; + + if (!te_init) typeeq_init(); + + ttable << "\ +/*\n\ + * This table is used by the pointer type-checker\n\ + */\n\ +static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = {\n"; + + e1 = (EqEntry *) typeeq_hash.first(); + while (e1) { + e2 = e1->next; + // Walk through the equivalency list + while (e2) { + if (e2->cast) + ttable << tab4 << "{ \"" << e1->name << "\",\"" << e2->name << "\"," << e2->cast << "},\n"; + else + ttable << tab4 << "{ \"" << e1->name << "\",\"" << e2->name << "\",0},\n"; + e2 = e2->next; + } + e1 = (EqEntry *) typeeq_hash.next(); + } + ttable << "{0,0,0}};\n"; + fprintf(f_wrappers,"%s\n", ttable.get()); + fprintf(f,"{\n"); + fprintf(f," int i;\n"); + fprintf(f," for (i = 0; _swig_mapping[i].n1; i++)\n"); + fprintf(f," SWIG_RegisterMapping(_swig_mapping[i].n1,_swig_mapping[i].n2,_swig_mapping[i].pcnv);\n"); + fprintf(f,"}\n"); + + String ctable; + ctable << "/*\n"; + ctable << "typedef struct {\n" + << " const char *name; \n" + << " void *(*convert)(void *);\n" + << "} SwigType;\n"; + + e1 = (EqEntry *) typeeq_hash.first(); + while (e1) { + e2 = e1->next; + ctable << "static SwigType " << e1->name << "[] = {"; + // Walk through the equivalency list + while (e2) { + ctable << "{ \"" << e2->name << "\", "; + if (e2->cast) + ctable << e2->cast << "},"; + else + ctable << "0},"; + e2 = e2->next; + } + ctable << "{0,0}};\n"; + e1 = (EqEntry *) typeeq_hash.next(); + } + ctable << "*/\n"; + fprintf(f_wrappers,"%s\n", ctable.get()); +} + +// ------------------------------------------------------------------------------ +// typeeq_derived(char *n1, char *n2, char *cast=) +// +// Adds a one-way mapping between datatypes. +// ------------------------------------------------------------------------------ + +void typeeq_derived(char *n1, char *n2, char *cast=0) { + DataType t,t1; + String name,name2; + EqEntry *e1; + + if (!te_init) typeeq_init(); + + t.type = T_USER; + t1.type = T_USER; + strcpy(t.name,n1); + strcpy(t1.name,n2); + name << t.print_mangle(); + name2 << t1.print_mangle(); + typeeq_add(name,name2,cast, &t1); +} + +// ------------------------------------------------------------------------------ +// typeeq_mangle(char *n1, char *n2, char *cast=) +// +// Adds a single type equivalence +// ------------------------------------------------------------------------------ + +void typeeq_mangle(char *n1, char *n2, char *cast=0) { + DataType t,t1; + String name,name2; + + if (!te_init) typeeq_init(); + + strcpy(t.name,n1); + strcpy(t1.name,n2); + name << t.print_mangle(); + name2 << t1.print_mangle(); + typeeq_add(name,name2,cast); +} + +// ------------------------------------------------------------------------------ +// typeeq_standard(void) +// +// Generate standard type equivalences (well, pointers that can map into +// other pointers naturally). +// +// ------------------------------------------------------------------------------- + +void typeeq_standard(void) { + + typeeq_mangle("int", "signed int"); + typeeq_mangle("int", "unsigned int"); + typeeq_mangle("signed int", "int"); + typeeq_mangle("unsigned int", "int"); + typeeq_mangle("short","signed short"); + typeeq_mangle("signed short","short"); + typeeq_mangle("short","unsigned short"); + typeeq_mangle("unsigned short","short"); + typeeq_mangle("long","signed long"); + typeeq_mangle("signed long","long"); + typeeq_mangle("long","unsigned long"); + typeeq_mangle("unsigned long","long"); + +} + +// ------------------------------------------------------------------------------ +// type_undefined_check(void) +// +// Checks the hash table for undefined datatypes and prints a warning message. +// ------------------------------------------------------------------------------- + +void type_undefined_check(void) { + char *s; + + s = (char *) undefined_types.first(); + if (s) { + fprintf(stderr,"The following datatypes were used, but undefined.\n"); + while (s) { + fprintf(stderr," %s\n",s); + s = (char *) undefined_types.next(); + } + } +} + + +// ---------------------------------------------------------------------- +// char *check_equivalent(DataType *t) +// +// Checks for type names equivalent to t. Returns a string with entries +// suitable for output. +// ---------------------------------------------------------------------- + +static char * +check_equivalent(DataType *t) { + EqEntry *e1, *e2; + static String out; + int npointer = t->is_pointer; + String m; + + out = ""; + while (t->is_pointer >= t->implicit_ptr) { + m = t->print_mangle(); + + if (!te_init) typeeq_init(); + e1 = (EqEntry *) typeeq_hash.first(); + while (e1) { + if (strcmp(m.get(),e1->name) == 0) { + e2 = e1->next; + while (e2) { + if (e2->type) { + e2->type->is_pointer += (npointer - t->is_pointer); + out << "{ \"" << e2->type->print_mangle() << "\","; + e2->type->is_pointer -= (npointer - t->is_pointer); + if (e2->cast) + out << e2->cast << "}, "; + else + out << "0}, "; + } + e2 = e2->next; + } + } + e1 = (EqEntry *) typeeq_hash.next(); + } + t->is_pointer--; + } + t->is_pointer = npointer; + out << "{0}"; + return out.get(); +} + +// ---------------------------------------------------------------------- +// void DataType::remember() +// +// Marks a datatype as being used in the interface file. We use this to +// construct a big table of pointer values at the end. +// ---------------------------------------------------------------------- + +static Hash remembered; + +void DataType::remember() { + DataType *t = new DataType(this); + remembered.add(t->print_mangle(),(void *) t); +} + +void +emit_type_table() { + char *key; + String types, table; + int i = 0; + + table << "static _swig_type_info *_swig_types_initial[] = {\n"; + key = remembered.firstkey(); + fprintf(f_runtime,"/* ---- TYPES TABLE (BEGIN) ---- */\n"); + while (key) { + fprintf(f_runtime,"#define SWIGTYPE%s _swig_types[%d] \n", key, i); + types << "static _swig_type_info _swigt_" << key << "[] = {"; + types << "{\"" << key << "\",0},"; + types << "{\"" << key << "\",0},"; + types << check_equivalent((DataType *)remembered.lookup(key)) << "};\n"; + table << "_swigt_" << key << ", \n"; + key = remembered.nextkey(); + i++; + } + table << "0\n};\n"; + fprintf(f_wrappers,"%s\n", types.get()); + fprintf(f_wrappers,"%s\n", table.get()); + fprintf(f_runtime,"static _swig_type_info *_swig_types[%d];\n", i+1); + fprintf(f_runtime,"/* ---- TYPES TABLE (END) ---- */\n\n"); + String init; + init << tab4 << "{\n" + << tab8 << "int i;\n" + << tab8 << "for (i = 0; _swig_types_initial[i]; i++) {\n" + << tab8 << tab4 << "_swig_types[i] = SWIG_TypeRegister(_swig_types_initial[i]);\n" + << tab8 << "}\n" + << tab4 << "}\n"; + fprintf(f_init,"%s", init.get()); +} + diff --git a/SWIG/Source/SWIG1.1/wrapfunc.cxx b/SWIG/Source/SWIG1.1/wrapfunc.cxx new file mode 100644 index 000000000..fbe7a3466 --- /dev/null +++ b/SWIG/Source/SWIG1.1/wrapfunc.cxx @@ -0,0 +1,211 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +// ------------------------------------------------------------------ +// wrapfunc.cxx +// +// Created : June 22, 1996 +// Dave Beazley +// +// This file defines a class for writing wrappers. Instead of worrying +// about I/O problems, this wrapper class can be used to write functions +// out of order. +// +// Defines 3 string objects. +// def - Wrapper function definition (function name and arguments) +// locals - Local variable definitions +// code - The actual wrapper function code +// +//------------------------------------------------------------------- + +#include "internal.h" +#include + +// ------------------------------------------------------------------- +// isolate the type name. This is a hack (sorry). +// ------------------------------------------------------------------- + +static String type_ext; +static char *isolate_type_name(char *tname) { + static String s; + s = ""; + while ((*tname) && (isalnum(*tname) || (*tname == '_') || (*tname == '$') || (*tname == ' '))) { + s << *tname; + tname++; + } + type_ext = ""; + type_ext = tname; + return s.get(); +} + +// ------------------------------------------------------------------- +// Print out a wrapper function. +// +// ------------------------------------------------------------------- + +void WrapperFunction::print(FILE *f) { + String *s; + s = (String *) localh.first(); + while (s) { + char *c = s->get(); + c[strlen(c)-1] = 0; + locals << tab4 << c << ";\n"; + s = (String *) localh.next(); + } + fprintf(f,"%s\n",def.get()); + fprintf(f,"%s",locals.get()); + fprintf(f,"%s\n",code.get()); +} + +// ------------------------------------------------------------------- +// Print out a wrapper function. +// +// ------------------------------------------------------------------- + +void WrapperFunction::print(String &f) { + String *s; + s = (String *) localh.first(); + while (s) { + char *c = s->get(); + c[strlen(c)-1] = 0; + locals << tab4 << c << ";\n"; + s = (String *) localh.next(); + } + + f << def << "\n" + << locals << "\n" + << code << "\n"; +} + +// ------------------------------------------------------------------- +// Safely add a local variable. +// +// Maintains a hash table to prevent double adding. +// ------------------------------------------------------------------- + +void WrapperFunction::add_local(char *type, char *name, char *defarg) { + char *stored_type; + char *new_type; + char temp[256],*c,*t; + + new_type = new char[strlen(type)+1]; + strcpy(new_type,type); + + // Figure out what the name of this variable is + + c = name; + t = temp; + while ((isalnum(*c) || (*c == '_') || (*c == '$')) && (*c)) { + *(t++) = *c; + c++; + } + *t = 0; + if (h.add(temp,new_type,WrapperFunction::del_type) == -1) { + // Check to see if a type mismatch has occurred + stored_type = (char *) h.lookup(temp); + if (strcmp(type,stored_type) != 0) + fprintf(stderr,"Error. Type %s conflicts with previously declared type of %s\n", + type, stored_type); + return; + } + + // See if any wrappers have been generated with this type + + char *tname = isolate_type_name(type); + String *lstr = (String *)localh.lookup(tname); + if (!lstr) { + lstr = new String; + *(lstr) << tname << " "; + localh.add(tname, (void *) lstr); + } + + // Successful, write some wrapper code + + if (!defarg) { + *(lstr) << type_ext << name << ","; + // locals << tab4 << type << " " << name << ";\n"; + } else { + *(lstr) << type_ext << name << "=" << defarg << ","; + // locals << tab4 << type << " " << name << " = " << defarg << ";\n"; + } +} + + +// ------------------------------------------------------------------- +// char *WrapperFunction::new_local(char *type, char *name, char *defarg) { +// +// A safe way to add a new local variable. type and name are used as +// a starting point, but a new local variable will be created if these +// are already in use. +// ------------------------------------------------------------------- + +char *WrapperFunction::new_local(char *type, char *name, char *defarg) { + char *new_type; + static String new_name; + char *c; + new_type = new char[strlen(type)+1]; + + strcpy(new_type,type); + new_name = ""; + c = name; + for (c = name; ((isalnum(*c) || (*c == '_') || (*c == '$')) && (*c)); c++) + new_name << *c; + + // Try to add a new local variable + if (h.add(new_name,new_type,WrapperFunction::del_type) == -1) { + // Local variable already exists, try to generate a new name + int i = 0; + new_name = ""; + // This is a little funky. We copy characters until we reach a nonvalid + // identifier symbol, add a number, then append the rest. This is + // needed to properly handle arrays. + c = name; + for (c = name; ((isalnum(*c) || (*c == '_') || (*c == '$')) && (*c)); c++) + new_name << *c; + new_name << i; + while (h.add(new_name,new_type,WrapperFunction::del_type) == -1) { + i++; + c = name; + new_name = ""; + for (c = name; ((isalnum(*c) || (*c == '_') || (*c == '$')) && (*c)); c++) + new_name << *c; + new_name << i; + } + } + new_name << c; + // Successful, write some wrapper code + if (!defarg) + locals << tab4 << type << " " << new_name << ";\n"; + else + locals << tab4 << type << " " << new_name << " = " << defarg << ";\n"; + + // Need to strip off the array symbols now + + c = new_name.get(); + while ((isalnum(*c) || (*c == '_') || (*c == '$')) && (*c)) + c++; + *c = 0; + return new_name; +} + +// ------------------------------------------------------------------ +// static WrapperFunction::del_type(void *obj) +// +// Callback function used when cleaning up the hash table. +// ------------------------------------------------------------------ + +void WrapperFunction::del_type(void *obj) { + delete (char *) obj; +} diff --git a/SWIG/Source/Swig/Makefile.in b/SWIG/Source/Swig/Makefile.in new file mode 100644 index 000000000..517849295 --- /dev/null +++ b/SWIG/Source/Swig/Makefile.in @@ -0,0 +1,24 @@ +# Generated automatically from Makefile.in by configure. + +CC = @CC@ +AR = @AR@ +RANLIB = @RANLIB@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +RPATH = @RPATH@ +SO = @SO@ +CCSHARED = @CCSHARED@ +LDSHARED = @LDSHARED@ +INCLUDE = -I. -I../DOH/Include + +SRCS = scanner.c include.c getopt.c misc.c +OBJS = scanner.o include.o getopt.o misc.o + +.c.o: + $(CC) $(CCSHARED) $(INCLUDE) $(CFLAGS) -c -o $*.o $< + +all: $(OBJS) + +clean: + rm -f *.o *~ core *.so *.a + diff --git a/SWIG/Source/Swig/getopt.c b/SWIG/Source/Swig/getopt.c new file mode 100644 index 000000000..d9ac2c4d1 --- /dev/null +++ b/SWIG/Source/Swig/getopt.c @@ -0,0 +1,110 @@ +/******************************************************************************* + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + *******************************************************************************/ + +#include "swigcore.h" + +/******************************************************************************* + * $Header$ + * + * File : getopt.c + * + * Functions for handling command line arguments. This is a little funky because + * the arguments are checked in multiple places. + *******************************************************************************/ + +static char **args; +static int numargs; +static int *marked; + +/* ----------------------------------------------------------------------------- + * void SWIG_init_args(int argc, char **argv) + * + * Initializes the argument list. + * ----------------------------------------------------------------------------- */ + +void +SWIG_init_args(int argc, char **argv) +{ + int i; + assert(argc > 0); + assert(argv); + + numargs = argc; + args = argv; + marked = (int *) malloc(numargs * sizeof(int)); + for (i = 0; i < argc; i++) { + marked[i] = 0; + } + marked[0] = 1; +} + +/* ----------------------------------------------------------------------------- + * void SWIG_mark_arg(int n) + * + * Marks an argument as being parsed. All modules should do this whenever they + * parse a command line option. + * ----------------------------------------------------------------------------- */ + +void +SWIG_mark_arg(int n) { + assert(marked); + assert((n >= 0) && (n < numargs)); + marked[n] = 1; +} + +/* ----------------------------------------------------------------------------- + * void SWIG_check_options() + * + * Checks for unparsed command line options. If so, issues an error and exits. + * ----------------------------------------------------------------------------- */ + +void SWIG_check_options() { + int error = 0; + int i; + assert(marked); + + for (i = 1; i < numargs-1; i++) { + if (!marked[i]) { + Printf(stderr,"swig error : Unrecognized option %s\n", args[i]); + error=1; + } + } + if (error) { + Printf(stderr,"Use 'swig -help' for available options.\n"); + exit(1); + } + if (marked[numargs-1]) { + Printf(stderr,"Must specify an input file. Use -help for available options.\n"); + exit(1); + } +} + +/* ----------------------------------------------------------------------------- + * void SWIG_arg_error() + * + * Generates a generic error message and exits. + * ----------------------------------------------------------------------------- */ + +void SWIG_arg_error() { + Printf(stderr,"SWIG : Unable to parse command line options.\n"); + Printf(stderr,"Use 'swig -help' for available options.\n"); + exit(1); +} + + + + + + diff --git a/SWIG/Source/Swig/include.c b/SWIG/Source/Swig/include.c new file mode 100644 index 000000000..cc1e46be4 --- /dev/null +++ b/SWIG/Source/Swig/include.c @@ -0,0 +1,204 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + +#include "swigcore.h" + +/******************************************************************************* + * $Header$ + * + * File : include.c + * + * Various file manipulation functions. + *******************************************************************************/ + +/* Delimeter used in accessing files and directories */ + +static DOH *directories = 0; /* List of include directories */ +static DOH *libdir = 0; /* SWIG library directory */ +static DOH *lastpath = 0; /* Last file that was included */ +static int bytes_read = 0; /* Bytes read */ + +/* ----------------------------------------------------------------------------- + * void SWIG_add_directory( DOH *dirname) + * + * Adds a directory to the SWIG search path. + * ----------------------------------------------------------------------------- */ + +void +SWIG_add_directory(DOH *dirname) +{ + if (!directories) directories = NewList(); + assert(directories); + if (!String_check(dirname)) { + dirname = NewString((char *) dirname); + assert(dirname); + } + Append(directories, dirname); +} + +/* ----------------------------------------------------------------------------- + * void SWIG_set_library(DOH *libname) + * + * Sets the language specific library name like 'tcl', 'perl5', 'python', etc... + * ----------------------------------------------------------------------------- */ + +void +SWIG_set_library(DOH *libname) +{ + Delete(libdir); + if (!String_check(libname)) { + libname = NewString((char *) libname); + assert(libname); + } + libdir = libname; +} + +/* ----------------------------------------------------------------------------- + * DOH *SWIG_get_library() + * + * Gets the language specific name like 'tcl', 'perl5', etc... + * ----------------------------------------------------------------------------- */ +DOH * +SWIG_get_library() { + assert(libdir); + return libdir; +} + +/* ----------------------------------------------------------------------------- + * DOH *SWIG_last_file() + * + * Returns the full pathname of the last file opened. + * ----------------------------------------------------------------------------- */ + +DOH * +SWIG_last_file() { + assert(lastpath); + return lastpath; +} + +/* ----------------------------------------------------------------------------- + * DOH *SWIG_search_path() + * + * Returns a list of the current search paths. + * ----------------------------------------------------------------------------- */ + +DOH *SWIG_search_path() +{ + DOH *filename; + DOH *dirname; + DOH *slist; + int i; + + slist = NewList(); + assert(slist); + filename = NewString(""); + assert(filename); + Printf(filename,".%s", FILE_DELIMETER); + Append(slist,filename); + for (i = 0; i < Len(directories); i++) { + dirname = Getitem(directories,i); + if (libdir) { + filename = NewString(""); + assert(filename); + Printf(filename,"%s%s%s%s", dirname, FILE_DELIMETER, libdir, FILE_DELIMETER); + Append(slist,filename); + } + filename = NewString(""); + assert(filename); + Printf(filename, "%s%s", dirname, FILE_DELIMETER); + Append(slist,filename); + } + return slist; +} + +/* ----------------------------------------------------------------------------- + * FILE *SWIG_open( DOH *name) + * + * Looks for a file and open it. + * ----------------------------------------------------------------------------- */ + +FILE * +SWIG_open(DOH *name) +{ + FILE *f; + DOH *filename; + DOH *spath = 0; + char *cname; + int i; + + if (!directories) directories = NewList(); + assert(directories); + + cname = Char(name); + filename = NewString(cname); + assert(filename); + f = fopen(Char(filename),"r"); + if (!f) { + spath = SWIG_search_path(); + for (i = 0; i < Len(spath); i++) { + Clear(filename); + Printf(filename,"%s%s", Getitem(spath,i), cname); + f = fopen(Char(filename),"r"); + if (f) break; + } + Delete(spath); + } + if (f) { + Delete(lastpath); + lastpath = Copy(filename); + } + Delete(filename); + return f; +} + +/* ----------------------------------------------------------------------------- + * DOH *SWIG_read_file(FILE *f) + * + * Reads data from f and returns as a new string + * ----------------------------------------------------------------------------- */ + +DOH *SWIG_read_file(FILE *f) { + char buffer[4096]; + DOH *str = NewString(""); + assert(str); + while (fgets(buffer,4095,f)) { + Append(str,buffer); + } + return str; +} + +/* ----------------------------------------------------------------------------- + * DOH *SWIG_include(DOH *name) + * + * Open a file and return it as a string. + * ----------------------------------------------------------------------------- */ + +DOH * +SWIG_include(DOH *name) +{ + FILE *f; + DOH *str; + f = SWIG_open(name); + if (!f) return 0; + str = SWIG_read_file(f); + bytes_read = bytes_read + Len(str); + fclose(f); + Seek(str,0,SEEK_SET); + Setfile(str,lastpath); + Setline(str,1); + /* fprintf(stderr,"%d bytes read\n", bytes_read); */ + return str; +} + diff --git a/SWIG/Source/Swig/misc.c b/SWIG/Source/Swig/misc.c new file mode 100644 index 000000000..cba44e62c --- /dev/null +++ b/SWIG/Source/Swig/misc.c @@ -0,0 +1,35 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + +#include "swigcore.h" + +/* ----------------------------------------------------------------------------- + * $Header$ + * + * misc.c + * ----------------------------------------------------------------------------- */ + +char *copy_string(const char *s) { + char *c = 0; + if (s) { + c = (char *) malloc(strlen(s)+1); + strcpy(c,s); + } + return c; +} + + + + diff --git a/SWIG/Source/Swig/scanner.c b/SWIG/Source/Swig/scanner.c new file mode 100644 index 000000000..d090c2640 --- /dev/null +++ b/SWIG/Source/Swig/scanner.c @@ -0,0 +1,749 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + + +#include "swigcore.h" + +struct Scanner { + DOH *text; /* Current token value */ + DOH *scanobjs; /* Objects being scanned */ + DOH *str; /* Current object being scanned */ + char *idstart; /* Optional identifier start characters */ + int nexttoken; /* Next token to be returned */ + int start_line; /* Starting line of certain declarations */ + int string_start; + int line; + int yylen; /* Length of text pushed into text */ + DOH *file; +}; + +#include + +/* ----------------------------------------------------------------------------- + * $Header$ + * + * scanner.c + * + * A generic C-based lexical scanner. + * ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * Scanner *NewScanner() - Create a new scanner object. + * ----------------------------------------------------------------------------- */ +Scanner *NewScanner() +{ + Scanner *s; + s = (Scanner *) malloc(sizeof(Scanner)); + s->line = 1; + s->file = 0; + s->nexttoken = -1; + s->start_line = 1; + s->string_start = 0; + s->yylen = 0; + s->idstart = ""; + s->scanobjs = NewList(); + s->text = NewString(""); + s->str = 0; + return s; +} + +/* ----------------------------------------------------------------------------- + * DelScanner(Scanner *s) - Delete a Scanner object + * ----------------------------------------------------------------------------- */ +void DelScanner(Scanner *s) +{ + assert(s); + Delete(s->scanobjs); + Delete(s->text); + Delete(s->file); + free(s); +} + +/* ----------------------------------------------------------------------------- + * Scanner_clear(Scanner *s) - Clear a scanner object + * ----------------------------------------------------------------------------- */ +void Scanner_clear(Scanner *s) { + assert(s); + Delete(s->str); + Clear(s->text); + Clear(s->scanobjs); + s->line = 1; + s->nexttoken = -1; + s->start_line = 0; + s->string_start = 0; + s->yylen = 0; +} + +/* ----------------------------------------------------------------------------- + * Scanner_push(Scanner *s, DOH *txt) - Push text into the scanner + * ----------------------------------------------------------------------------- */ + +void Scanner_push(Scanner *s, DOH *txt) +{ + assert(s && txt); + Push(s->scanobjs,txt); + if (s->str) Delete(s->str); + s->str = txt; + Incref(s->str); + s->line = Getline(txt); +} +/* ----------------------------------------------------------------------------- + * Scanner_pushtoken(Scanner *s, int nt) + * + * Set the next processing token. + * ----------------------------------------------------------------------------- */ + +void Scanner_pushtoken(Scanner *s, int nt) { + assert(s); + assert((nt >= 0) && (nt < MAXTOKENS)); + s->nexttoken = nt; +} + +/* ----------------------------------------------------------------------------- + * Scanner_set_location(Scanner *s, DOH *file, int line) + * ----------------------------------------------------------------------------- */ +void +Scanner_set_location(Scanner *s, DOH *file, int line) +{ + Setline(s->str,line); + Setfile(s->str,file); +} + +/* ----------------------------------------------------------------------------- + * Scanner_get_file(Scanner *s) - Get current file + * ----------------------------------------------------------------------------- */ + +DOH * +Scanner_get_file(Scanner *s) { + return Getfile(s->str); +} + +int +Scanner_get_line(Scanner *s) { + return Getline(s->str); +} + +/* ----------------------------------------------------------------------------- + * char nextchar(Scanner *s) + * + * Returns the next character from the scanner or 0 if end of the string. + * ----------------------------------------------------------------------------- */ +static char +nextchar(Scanner *s) +{ + char c[2] = {0,0}; + int nc; + if (!s->str) return 0; + while ((nc = Getc(s->str)) == EOF) { + Delete(s->str); + s->str = 0; + Delitem(s->scanobjs,0); + if (Len(s->scanobjs) == 0) return 0; + s->str = Getitem(s->scanobjs,0); + s->line = Getline(s->str); + if (s->str) + Incref(s->str); + } + if (nc == '\n') s->line++; + c[0] = (char) nc; + c[1] = 0; + Append(s->text,c); + return c[0]; +} + +/* ----------------------------------------------------------------------------- + * void retract(Scanner *s, int n) + * + * Retract n characters + * ----------------------------------------------------------------------------- */ +static void +retract(Scanner *s, int n) { + int i, l; + char *str; + + str = Char(s->text); + l = Len(s->text); + assert(n <= l); + for (i = 0; i < n; i++) { + if (str[l-1] == '\n') { + s->line--; + } + /* // Ungetc(str[l-1],s->str); */ + Seek(s->str,-1, SEEK_CUR); + Delitem(s->text,DOH_END); + } +} + +/* ----------------------------------------------------------------------------- + * int look(Scanner *s) + * + * Get the next token. + * ----------------------------------------------------------------------------- */ + +static int +look(Scanner *s) +{ + int state; + char c = 0; + + state = 0; + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + while(1) { + switch(state) { + case 0 : + if((c = nextchar(s)) == 0) return(0); + + /* Process delimeters */ + + if (c == '\n') { + return TOKEN_ENDLINE; + } else if (!isspace(c)) { + retract(s,1); + state = 1000; + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + } + break; + + case 1000: + if ((c = nextchar(s)) == 0) return (0); + if (c == '%') state = 4; /* Possibly a SWIG directive */ + + /* Look for possible identifiers */ + + else if ((isalpha(c)) || (c == '_') || (strchr(s->idstart,c))) state = 7; + + /* Look for single character symbols */ + + else if (c == '(') return TOKEN_LPAREN; + else if (c == ')') return TOKEN_RPAREN; + else if (c == ';') return TOKEN_SEMI; + else if (c == ',') return TOKEN_COMMA; + else if (c == '*') return TOKEN_STAR; + else if (c == '}') return TOKEN_RBRACE; + else if (c == '{') return TOKEN_LBRACE; + else if (c == '=') state = 33; + else if (c == '+') return TOKEN_PLUS; + else if (c == '-') return TOKEN_MINUS; + else if (c == '&') state = 31; + else if (c == '|') state = 32; + else if (c == '^') return TOKEN_XOR; + else if (c == '<') state = 60; + else if (c == '>') state = 61; + else if (c == '~') return TOKEN_NOT; + else if (c == '!') state = 3; + else if (c == '\\') return TOKEN_BACKSLASH; + else if (c == '[') return TOKEN_LBRACKET; + else if (c == ']') return TOKEN_RBRACKET; + else if (c == '@') return TOKEN_AT; + else if (c == '$') return TOKEN_DOLLAR; + else if (c == '#') return TOKEN_POUND; + + /* Look for multi-character sequences */ + + else if (c == '/') state = 1; /* Comment (maybe) */ + else if (c == '\"') { + state = 2; /* Possibly a string */ + s->string_start = s->line; + } + + else if (c == ':') state = 5; /* maybe double colon */ + else if (c == '0') state = 83; /* An octal or hex value */ + else if (c == '\'') { + s->string_start = s->line; + state = 9; /* A character constant */ + } + else if (c == '.') state = 100; /* Maybe a number, maybe just a period */ + else if (isdigit(c)) state = 8; /* A numerical value */ + else state = 99; /* An error */ + break; + + case 1: /* Comment block */ + if ((c = nextchar(s)) == 0) return(0); + if (c == '/') { + state = 10; /* C++ style comment */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + + Append(s->text," "); + } else if (c == '*') { + state = 11; /* C style comment */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + Append(s->text," "); + } else { + retract(s,1); + return TOKEN_SLASH; + } + break; + case 10: /* C++ style comment */ + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated comment",comment_start); */ + return 0; + } + if (c == '\n') { + return TOKEN_ENDLINE; + } else { + state = 10; + } + break; + case 11: /* C style comment block */ + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated comment",comment_start); */ + return 0; + } + if (c == '*') { + state = 12; + } else { + state = 11; + } + break; + case 12: /* Still in C style comment */ + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated comment",comment_start); */ + return 0; + } + if (c == '*') { + state = 12; + } else if (c == '/') { + Clear(s->text); + state = 0; + } else { + state = 11; + } + break; + + case 2: /* Processing a string */ + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated string", string_start); */ + return 0; + } + if (c == '\"') { + return TOKEN_STRING; + } else if (c == '\\') { + state = 21; /* Possibly an escape sequence. */ + break; + } else state = 2; + break; + case 21: /* An escape sequence. get next character, then go + back to processing strings */ + if ((c = nextchar(s)) == 0) return 0; + state = 2; + break; + + case 3: /* Maybe a not equals */ + if ((c = nextchar(s)) == 0) return TOKEN_LNOT; + else if (c == '=') return TOKEN_NOTEQUAL; + else { + retract(s,1); + return TOKEN_LNOT; + } + break; + + case 31: /* AND or Logical AND */ + if ((c = nextchar(s)) == 0) return TOKEN_AND; + else if (c == '&') return TOKEN_LAND; + else { + retract(s,1); + return TOKEN_AND; + } + break; + + case 32: /* OR or Logical OR */ + if ((c = nextchar(s)) == 0) return TOKEN_OR; + else if (c == '|') return TOKEN_LOR; + else { + retract(s,1); + return TOKEN_OR; + } + break; + + case 33: /* EQUAL or EQUALTO */ + if ((c = nextchar(s)) == 0) return TOKEN_EQUAL; + else if (c == '=') return TOKEN_EQUALTO; + else { + retract(s,1); + return TOKEN_EQUAL; + } + break; + + case 4: /* A wrapper generator directive (maybe) */ + if (( c= nextchar(s)) == 0) return TOKEN_PERCENT; + if (c == '{') { + state = 40; /* Include block */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + s->start_line = s->line; + } + else if (strchr(s->idstart,'%') && ((isalpha(c)) || (c == '_'))) state = 7; + else { + retract(s,1); + return TOKEN_PERCENT; + } + break; + + case 40: /* Process an include block */ + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated code block.", start_line); */ + return 0; + } + if (c == '%') state = 41; + break; + case 41: /* Still processing include block */ + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated code block.", start_line); */ + return 0; + } + if (c == '}') { + Delitem(s->text,DOH_END); + Delitem(s->text,DOH_END); + return TOKEN_CODEBLOCK; + } else { + state = 40; + } + break; + + case 5: /* Maybe a double colon */ + + if (( c = nextchar(s)) == 0) return TOKEN_COLON; + if ( c == ':') return TOKEN_DCOLON; + else { + retract(s,1); + return TOKEN_COLON; + } + break; + + case 60: /* shift operators */ + if ((c = nextchar(s)) == 0) return TOKEN_LESSTHAN; + if (c == '<') return TOKEN_LSHIFT; + else if (c == '=') return TOKEN_LTEQUAL; + else { + retract(s,1); + return TOKEN_LESSTHAN; + } + break; + case 61: + if ((c = nextchar(s)) == 0) return TOKEN_GREATERTHAN; + if (c == '>') return TOKEN_RSHIFT; + else if (c == '=') return TOKEN_GTEQUAL; + else { + retract(s,1); + return TOKEN_GREATERTHAN; + } + break; + case 7: /* Identifier */ + if ((c = nextchar(s)) == 0) return TOKEN_ID; + if (isalnum(c) || (c == '_') || (c == '$')) { + state = 7; + } else { + retract(s,1); + return TOKEN_ID; + } + break; + case 8: /* A numerical digit */ + if ((c = nextchar(s)) == 0) return TOKEN_INT; + if (c == '.') {state = 81;} + else if ((c == 'e') || (c == 'E')) {state = 86;} + else if ((c == 'f') || (c == 'F')) { + Delitem(s->text,DOH_END); + return TOKEN_FLOAT; + } else if (isdigit(c)) { state = 8;} + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s,1); + return TOKEN_INT; + } + break; + case 81: /* A floating pointer number of some sort */ + if ((c = nextchar(s)) == 0) return TOKEN_DOUBLE; + if (isdigit(c)) state = 81; + else if ((c == 'e') || (c == 'E')) state = 82; + else if ((c == 'f') || (c == 'F') || (c == 'l') || (c == 'L')) { + Delitem(s->text,DOH_END); + return TOKEN_FLOAT; + } else { + retract(s,1); + return(TOKEN_DOUBLE); + } + break; + case 82: + if ((c = nextchar(s)) == 0) { + retract(s,1); + return TOKEN_INT; + } + if ((isdigit(c)) || (c == '-') || (c == '+')) state = 86; + else { + retract(s,2); + return(TOKEN_INT); + } + break; + case 83: + /* Might be a hexidecimal or octal number */ + if ((c = nextchar(s)) == 0) return TOKEN_INT; + if (isdigit(c)) state = 84; + else if ((c == 'x') || (c == 'X')) state = 85; + else if (c == '.') state = 81; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s,1); + return TOKEN_INT; + } + break; + case 84: + /* This is an octal number */ + if ((c = nextchar(s)) == 0) return TOKEN_INT; + if (isdigit(c)) state = 84; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s,1); + return TOKEN_INT; + } + break; + case 85: + /* This is an hex number */ + if ((c = nextchar(s)) == 0) return TOKEN_INT; + if ((isdigit(c)) || (c=='a') || (c=='b') || (c=='c') || + (c=='d') || (c=='e') || (c=='f') || (c=='A') || + (c=='B') || (c=='C') || (c=='D') || (c=='E') || + (c=='F')) + state = 85; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s,1); + return TOKEN_INT; + } + break; + + case 86: + /* Rest of floating point number */ + + if ((c = nextchar(s)) == 0) return TOKEN_DOUBLE; + if (isdigit(c)) state = 86; + else if ((c == 'f') || (c == 'F')) { + Delitem(s->text,DOH_END); + return TOKEN_FLOAT; + } else if ((c == 'l') || (c == 'L')) { + Delitem(s->text,DOH_END); + return TOKEN_DOUBLE; + } else { + retract(s,1); + return TOKEN_DOUBLE; + } + break; + + case 87 : + /* A long integer of some sort */ + if ((c = nextchar(s)) == 0) return TOKEN_LONG; + if ((c == 'u') || (c == 'U')) { + return TOKEN_ULONG; + } else { + retract(s,1); + return TOKEN_LONG; + } + + /* An unsigned number */ + case 88: + + if ((c = nextchar(s)) == 0) return TOKEN_UINT; + if ((c == 'l') || (c == 'L')) { + return TOKEN_ULONG; + } else { + retract(s,1); + return TOKEN_UINT; + } + + /* A character constant */ + case 9: + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated character constant", string_start); */ + return 0; + } + if (c == '\'') { + return(TOKEN_CHAR); + } else if (c == '\\') state = 91; + break; + + case 91: + if ((c = nextchar(s)) == 0) { + /* add_error(0,"Unterminated character constant", string_start); */ + return 0; + } + state = 9; + break; + + /* A period or maybe a floating point number */ + + case 100: + if ((c = nextchar(s)) == 0) return (0); + if (isdigit(c)) state = 81; + else { + retract(s,1); + return TOKEN_PERIOD; + } + break; + + /* An illegal character */ + default: + return TOKEN_ILLEGAL; + } + } +} + +/* ----------------------------------------------------------------------------- + * int Scanner_token(Scanner *s) + * + * Return the next token or 0 if at the end of the string + * ----------------------------------------------------------------------------- */ + +int +Scanner_token(Scanner *s) +{ + int t; + Clear(s->text); + if (s->nexttoken >= 0) { + t = s->nexttoken; + s->nexttoken = -1; + return t; + } + t = look(s); + return t; +} + +/* ----------------------------------------------------------------------------- + * DOH *Scanner_text(Scanner *s) + * + * Return the text associated with the last token returned. + * ----------------------------------------------------------------------------- */ +DOH * +Scanner_text(Scanner *s) +{ + return s->text; +} + +/* ----------------------------------------------------------------------------- + * void Scanner_skip_line(Scanner *s) + * + * Skips to the end of a line + * ----------------------------------------------------------------------------- */ + +void +Scanner_skip_line(Scanner *s) +{ + char c; + int done = 0; + Clear(s->text); + Setfile(s->text,Getfile(s->str)); + Setline(s->text,Getline(s->str)); + while (!done) { + if ((c = nextchar(s)) == 0) return; + if (c == '\\') c = nextchar(s); + else if (c == '\n') done = 1; + } + return; +} + +/* ----------------------------------------------------------------------------- + * void Scanner_skip_balanced(Scanner *s, int start, int end) + * + * Skips a piece of code enclosed in begin/end symbols such as '{...}' or + * (...). Ignores symbols inside comments or strings. + * ----------------------------------------------------------------------------- */ + +int +Scanner_skip_balanced(Scanner *s, int startchar, int endchar) +{ + char c; + int num_levels = 1; + int l; + int state = 0; + char temp[2] = {0,0}; + l = s->line; + temp[0] = (char) startchar; + Clear(s->text); + Setfile(s->text,Getfile(s->str)); + Setline(s->text,Getline(s->str)); + + Append(s->text,temp); + while (num_levels > 0) { + if ((c = nextchar(s)) == 0) { + return -1; + } + switch(state) { + case 0: + if (c == startchar) num_levels++; + else if (c == endchar) num_levels--; + else if (c == '/') state = 10; + else if (c == '\"') state = 20; + else if (c == '\'') state = 30; + break; + case 10: + if (c == '/') state = 11; + else if (c == '*') state = 12; + else state = 0; + break; + case 11: + if (c == '\n') state = 0; + else state = 11; + break; + case 12: + if (c == '*') state = 13; + break; + case 13: + if (c == '*') state = 13; + else if (c == '/') state = 0; + else state = 12; + break; + case 20: + if (c == '\"') state = 0; + else if (c == '\\') state = 21; + break; + case 21: + state = 20; + break; + case 30: + if (c == '\'') state = 0; + else if (c == '\\') state = 31; + break; + case 31: + state = 30; + break; + default: + break; + } + } + return 0; +} + + + + diff --git a/SWIG/Source/Swig/swigcore.h b/SWIG/Source/Swig/swigcore.h new file mode 100644 index 000000000..dd136ea3e --- /dev/null +++ b/SWIG/Source/Swig/swigcore.h @@ -0,0 +1,127 @@ +/**************************************************************************** + * Simplified Wrapper and Interface Generator (SWIG) + * + * Author : David Beazley + * + * Department of Computer Science + * University of Chicago + * 1100 E 58th Street + * Chicago, IL 60637 + * beazley@cs.uchicago.edu + * + * Please read the file LICENSE for the copyright and terms by which SWIG + * can be used and distributed. + ****************************************************************************/ + +#ifndef _SWIGCORE_H +#define _SWIGCORE_H + +#include +#include +#include +#include +#include "doh.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* --- File interface --- */ + +extern void SWIG_add_directory(DOH *dirname); +extern void SWIG_set_library(DOH *libname); +extern DOH *SWIG_get_library(); +extern DOH *SWIG_last_file(); +extern DOH *SWIG_search_path(); +extern FILE *SWIG_open(DOH *name); +extern DOH *SWIG_read_file(FILE *f); +extern DOH *SWIG_include(DOH *name); + +#define FILE_DELIMETER "/" + +/* --- Command line parsing --- */ +extern void SWIG_init_args(int argc, char **argv); +extern void SWIG_mark_arg(int n); +extern void SWIG_check_options(); +extern void SWIG_arg_error(); + + +/* --- Scanner Interface --- */ + +typedef struct Scanner Scanner; +extern Scanner *NewScanner(); +extern void DelScanner(Scanner *); +extern void Scanner_clear(Scanner *); +extern void Scanner_push(Scanner *, DOH *); +extern void Scanner_pushtoken(Scanner *, int); +extern int Scanner_token(Scanner *); +extern DOH *Scanner_text(Scanner *); +extern void Scanner_skip_line(Scanner *); +extern int Scanner_skip_balanced(Scanner *, int startchar, int endchar); +extern void Scanner_set_location(Scanner *, DOH *file, int line); +extern DOH *Scanner_get_file(Scanner *); +extern int Scanner_get_line(Scanner *); + +#define MAXTOKENS 512 +#define TOKEN_LPAREN 1 +#define TOKEN_RPAREN 2 +#define TOKEN_SEMI 3 +#define TOKEN_COMMA 4 +#define TOKEN_STAR 5 +#define TOKEN_LBRACE 6 +#define TOKEN_RBRACE 7 +#define TOKEN_EQUAL 8 +#define TOKEN_EQUALTO 9 +#define TOKEN_NOTEQUAL 10 +#define TOKEN_PLUS 11 +#define TOKEN_MINUS 12 +#define TOKEN_AND 13 +#define TOKEN_LAND 14 +#define TOKEN_OR 15 +#define TOKEN_LOR 16 +#define TOKEN_XOR 17 +#define TOKEN_LESSTHAN 18 +#define TOKEN_GREATERTHAN 19 +#define TOKEN_LTEQUAL 20 +#define TOKEN_GTEQUAL 21 +#define TOKEN_NOT 22 +#define TOKEN_LNOT 23 +#define TOKEN_LBRACKET 24 +#define TOKEN_RBRACKET 25 +#define TOKEN_SLASH 26 +#define TOKEN_BACKSLASH 27 +#define TOKEN_ENDLINE 28 +#define TOKEN_STRING 29 +#define TOKEN_POUND 30 +#define TOKEN_PERCENT 31 +#define TOKEN_COLON 32 +#define TOKEN_DCOLON 33 +#define TOKEN_LSHIFT 34 +#define TOKEN_RSHIFT 35 +#define TOKEN_ID 36 +#define TOKEN_FLOAT 37 +#define TOKEN_DOUBLE 38 +#define TOKEN_INT 39 +#define TOKEN_UINT 40 +#define TOKEN_LONG 41 +#define TOKEN_ULONG 42 +#define TOKEN_CHAR 43 +#define TOKEN_PERIOD 44 +#define TOKEN_AT 45 +#define TOKEN_DOLLAR 46 +#define TOKEN_CODEBLOCK 47 +#define TOKEN_ILLEGAL 98 +#define TOKEN_LAST 99 + + +extern char *copy_string(const char *c); + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/SWIG/Source/configure.in b/SWIG/Source/configure.in new file mode 100644 index 000000000..c389be24f --- /dev/null +++ b/SWIG/Source/configure.in @@ -0,0 +1,172 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(Core/swigcore.h) +AC_PREREQ(2.0) + +# Set name for machine-dependent library files +AC_SUBST(MACHDEP) +AC_MSG_CHECKING(MACHDEP) +if test -z "$MACHDEP" +then + if test -f /usr/lib/NextStep/software_version; then + set X `hostinfo | grep 'NeXT Mach.*:' | \ + sed -e 's/://' -e 's/\./_/'` && \ + ac_sys_system=next && ac_sys_release=$4 + MACHDEP="$ac_sys_system$ac_sys_release$ac_sys_cpu" + else + ac_sys_system=`uname -s` + if test "$ac_sys_system" = "AIX" ; then + ac_sys_release=`uname -v` + else + ac_sys_release=`uname -r` + fi + ac_md_system=`echo $ac_sys_system | + tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'` + ac_md_release=`echo $ac_sys_release | + tr -d '[/ ]' | sed 's/\..*//'` + MACHDEP="$ac_md_system$ac_md_release" + fi + case MACHDEP in + '') MACHDEP=unknown;; + esac +fi +AC_MSG_RESULT($MACHDEP) + +AC_PROG_CC +AC_PROG_CXX +AC_PROG_RANLIB + +dnl Checks for programs. + +AC_SUBST(AR) +AC_CHECK_PROGS(AR, ar aal, ar) + +dnl Checks for header files. +AC_HEADER_STDC +dnl Checks for library functions. + +# Set info about shared libraries. +AC_SUBST(SO) +AC_SUBST(LDSHARED) +AC_SUBST(CCSHARED) + +# SO is the extension of shared libraries `(including the dot!) +# -- usually .so, .sl on HP-UX +AC_MSG_CHECKING(SO) +if test -z "$SO" +then + case $ac_sys_system in + hp*|HP*) SO=.sl;; + *) SO=.so;; + esac +fi +AC_MSG_RESULT($SO) +# LDSHARED is the ld *command* used to create shared library +# -- "ld" on SunOS 4.x.x, "ld -G" on SunOS 5.x, "ld -shared" on IRIX 5 +# (Shared libraries in this instance are shared modules to be loaded into +# Python, as opposed to building Python itself as a shared library.) +AC_MSG_CHECKING(LDSHARED) +if test -z "$LDSHARED" +then + case $ac_sys_system/$ac_sys_release in + AIX*) LDSHARED="\$(srcdir)/ld_so_aix \$(CC)";; + IRIX/5*) LDSHARED="ld -shared";; + IRIX*/6*) LDSHARED="ld ${SGI_ABI} -shared -all";; + SunOS/4*) LDSHARED="ld";; + SunOS/5*) LDSHARED="ld -G";; + hp*|HP*) LDSHARED="ld -b";; + OSF*) LDSHARED="ld -shared -expect_unresolved \"*\"";; + DYNIX/ptx*) LDSHARED="ld -G";; + next/*) + if test "$ns_dyld" + then LDSHARED='$(CC) $(LDFLAGS) -bundle -prebind' + else LDSHARED='$(CC) $(CFLAGS) -nostdlib -r'; + fi + if test "$with_next_framework" ; then + LDSHARED="$LDSHARED \$(LDLIBRARY)" + fi ;; + Linux*) LDSHARED="gcc -shared";; + dgux*) LDSHARED="ld -G";; + FreeBSD*/3*) LDSHARED="gcc -shared";; + FreeBSD*|OpenBSD*) LDSHARED="ld -Bshareable";; + NetBSD*) + if [[ "`$CC -dM -E -