/******************************************************************************* * 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) { 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); } } else { if (insert_file("pyexp.swg", f_header) == -1) { fprintf(stderr,"SWIG : Fatal error. Unable to locate pyexp.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 ((strncmp(name, "new_", 4) != 0) && // don't use the out typemap for constructors (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; } }