/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * * All use of this software is subject to the terms of the revised BSD * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * * @file interfaceMakerC.cxx * @author drose * @date 2001-09-25 */ #include "interfaceMakerC.h" #include "interrogateBuilder.h" #include "interrogate.h" #include "functionRemap.h" #include "parameterRemapHandleToInt.h" #include "parameterRemapUnchanged.h" #include "typeManager.h" #include "interrogateDatabase.h" #include "interrogateType.h" #include "interrogateFunction.h" #include "cppFunctionType.h" using std::ostream; /** * */ InterfaceMakerC:: InterfaceMakerC(InterrogateModuleDef *def) : InterfaceMaker(def) { } /** * */ InterfaceMakerC:: ~InterfaceMakerC() { } /** * Generates the list of function prototypes corresponding to the functions * that will be output in write_functions(). */ void InterfaceMakerC:: write_prototypes(ostream &out,ostream *out_h) { // The 'used' attribute prevents emscripten from optimizing it out. out << "#if __GNUC__ >= 4\n" "#define EXPORT_FUNC extern \"C\" __attribute__((used, visibility(\"default\")))\n" "#else\n" "#define EXPORT_FUNC extern \"C\"\n" "#endif\n\n"; FunctionsByIndex::iterator fi; for (fi = _functions.begin(); fi != _functions.end(); ++fi) { Function *func = (*fi).second; write_prototype_for(out, func); } out << "\n"; InterfaceMaker::write_prototypes(out,out_h); } /** * Generates the list of functions that are appropriate for this interface. * This function is called *before* write_prototypes(), above. */ void InterfaceMakerC:: write_functions(ostream &out) { FunctionsByIndex::iterator fi; for (fi = _functions.begin(); fi != _functions.end(); ++fi) { Function *func = (*fi).second; write_function_for(out, func); } InterfaceMaker::write_functions(out); } /** * Allocates a new ParameterRemap object suitable to the indicated parameter * type. If struct_type is non-NULL, it is the type of the enclosing class * for the function (method) in question. * * The return value is a newly-allocated ParameterRemap object, if the * parameter type is acceptable, or NULL if the parameter type cannot be * handled. */ ParameterRemap *InterfaceMakerC:: remap_parameter(CPPType *struct_type, CPPType *param_type) { // Wrap TypeHandle and ButtonHandle, which are practically just ints, as an // integer instead of a pointer. It makes things easier on the scripting // language, especially if there has to be a dynamic downcasting system on // the scripting language side. if (TypeManager::is_handle(param_type)) { return new ParameterRemapHandleToInt(param_type); } else { return InterfaceMaker::remap_parameter(struct_type, param_type); } } /** * This method should be overridden and redefined to return true for * interfaces that require the implicit "this" parameter, if present, to be * passed as the first parameter to any wrapper functions. */ bool InterfaceMakerC:: synthesize_this_parameter() { return true; } /** * Returns the prefix string used to generate wrapper function names. */ std::string InterfaceMakerC:: get_wrapper_prefix() { return "_inC"; } /** * Returns the prefix string used to generate unique symbolic names, which are * not necessarily C-callable function names. */ std::string InterfaceMakerC:: get_unique_prefix() { return "c"; } /** * Associates the function wrapper with its function in the appropriate * structures in the database. */ void InterfaceMakerC:: record_function_wrapper(InterrogateFunction &ifunc, FunctionWrapperIndex wrapper_index) { ifunc._c_wrappers.push_back(wrapper_index); } /** * Writes the prototype for the indicated function. */ void InterfaceMakerC:: write_prototype_for(ostream &out, InterfaceMaker::Function *func) { Function::Remaps::const_iterator ri; for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { FunctionRemap *remap = (*ri); if (remap->_extension || (remap->_flags & FunctionRemap::F_explicit_self)) { continue; } if (output_function_names) { out << "EXPORT_FUNC "; } write_function_header(out, func, remap, false); out << ";\n"; } } /** * Writes the definition for a function that will call the indicated C++ * function or method. */ void InterfaceMakerC:: write_function_for(ostream &out, InterfaceMaker::Function *func) { Function::Remaps::const_iterator ri; for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { FunctionRemap *remap = (*ri); write_function_instance(out, func, remap); } } /** * Writes out the particular function that handles a single instance of an * overloaded function. */ void InterfaceMakerC:: write_function_instance(ostream &out, InterfaceMaker::Function *func, FunctionRemap *remap) { if (remap->_extension || (remap->_flags & FunctionRemap::F_explicit_self)) { return; } out << "/*\n" << " * C wrapper for\n" << " * "; remap->write_orig_prototype(out, 0, false, remap->_num_default_parameters); out << "\n" << " */\n"; if (!output_function_names) { // If we're not saving the function names, don't export it from the // library. out << "static "; } write_function_header(out, func, remap, true); out << " {\n"; if (generate_spam) { write_spam_message(out, remap); } std::string return_expr = remap->call_function(out, 2, true, "param0"); return_expr = manage_return_value(out, 2, remap, return_expr); if (!return_expr.empty()) { out << " return " << return_expr << ";\n"; } out << "}\n\n"; } /** * Writes the first line of a function definition, either for a prototype or a * function body. */ void InterfaceMakerC:: write_function_header(ostream &out, InterfaceMaker::Function *func, FunctionRemap *remap, bool newline) { if (remap->_void_return) { out << "void"; } else { out << remap->_return_type->get_new_type()->get_local_name(&parser); } if (newline) { out << "\n"; } else { out << " "; } out << remap->_wrapper_name << "("; int pn = 0; if (pn < (int)remap->_parameters.size()) { remap->_parameters[pn]._remap->get_new_type()-> output_instance(out, remap->get_parameter_name(pn), &parser); pn++; while (pn < (int)remap->_parameters.size()) { out << ", "; remap->_parameters[pn]._remap->get_new_type()-> output_instance(out, remap->get_parameter_name(pn), &parser); pn++; } } out << ")"; }