/******************************************************************************* * 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_header[]; fprintf(f, "/*\n\ * FILE : %s\n\ * \n\ * This file was automatically generated by :\n\ * Simplified Wrapper and Interface Generator (SWIG)\n\ * Version %d.%d %s\n\ * \n\ * Portions Copyright (c) 1995-1998\n\ * The University of Utah and The Regents of the University of California.\n\ * Permission is granted to distribute this file in any manner provided\n\ * this notice remains intact.\n\ * \n\ * Do not make changes to this file--changes will be lost!\n\ *\n\ */\n\n", fn_header, 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; }