diff --git a/direct/src/ffi/FFIOverload.py b/direct/src/ffi/FFIOverload.py index 1e97f89b9a..d2f527a791 100644 --- a/direct/src/ffi/FFIOverload.py +++ b/direct/src/ffi/FFIOverload.py @@ -20,6 +20,7 @@ AT_bool = 4 AT_char = 5 AT_void = 6 AT_string = 7 +AT_longlong = 8 def cullOverloadedMethods(fullMethodDict): """ @@ -65,6 +66,9 @@ def getTypeName(classTypeDesc, typeDesc): (typeDesc.atomicType == AT_double)): return 'types.FloatType' + elif ((typeDesc.atomicType == AT_longlong)): + return 'types.LongType' + # Strings are treated as Python strings elif ((typeDesc.atomicType == AT_string)): return 'types.StringType' @@ -416,8 +420,9 @@ class FFIMethodArgumentTree: # Otherwise, we'll check the particular type of # the object. condition = '(isinstance(_args[' + `level` + '], ' + typeName + '))' - # If it is looking for a float, make it accept an integer too - if (typeName == 'types.FloatType'): + # If it is looking for a float or a long, make it + # accept an integer too + if (typeName == 'types.FloatType' or typeName == 'types.LongType'): condition += (' or (isinstance(_args[' + `level` + '], ' + 'types.IntType' + '))') diff --git a/direct/src/ffi/FFISpecs.py b/direct/src/ffi/FFISpecs.py index ebb5e59750..800d4cbe0f 100644 --- a/direct/src/ffi/FFISpecs.py +++ b/direct/src/ffi/FFISpecs.py @@ -41,13 +41,18 @@ class FunctionSpecification: typeName = FFIOverload.getTypeName(methodClass, typeDesc) # Special case: - # If it is looking for a float, accept an int as well + # If it is looking for a float or a long, accept an int as well # C++ will cast it properly, and it is much more convenient if (typeName == 'types.FloatType'): indent(file, nesting, 'assert((isinstance(' + methodArgSpec.name + ', types.FloatType) or isinstance(' + methodArgSpec.name + ', types.IntType)))\n') + elif (typeName == 'types.LongType'): + indent(file, nesting, 'assert((isinstance(' + + methodArgSpec.name + ', types.LongType) or isinstance(' + + methodArgSpec.name + ', types.IntType)))\n') + elif typeDesc.__class__ != FFITypes.PyObjectTypeDescriptor: # Get the real return type (not derived) if ((not typeDesc.isNested) and diff --git a/direct/src/ffi/FFITypes.py b/direct/src/ffi/FFITypes.py index 50043cbe21..8c23a0c199 100644 --- a/direct/src/ffi/FFITypes.py +++ b/direct/src/ffi/FFITypes.py @@ -56,6 +56,7 @@ class BaseTypeDescriptor: # AT_char = 5 # AT_void = 6 # AT_string = 7 + # AT_longlong = 8 # By default this type is not atomic self.atomicType = 0 diff --git a/dtool/src/interrogate/interfaceMakerPythonObj.cxx b/dtool/src/interrogate/interfaceMakerPythonObj.cxx index 629f9c9e8e..1352207876 100644 --- a/dtool/src/interrogate/interfaceMakerPythonObj.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonObj.cxx @@ -321,6 +321,9 @@ write_function_instance(ostream &out, int indent_level, string format_specifiers; string parameter_list; vector_string pexprs; + string extra_convert; + string extra_param_check; + string extra_cleanup; // Make one pass through the parameter list. We will output a // one-line temporary variable definition for each parameter, while @@ -371,6 +374,26 @@ write_function_instance(ostream &out, int indent_level, pexpr_string = "(PyObject_IsTrue(" + param_name + ")!=0)"; expected_params += "bool"; + } else if (TypeManager::is_unsigned_longlong(type)) { + out << "PyObject *" << param_name; + format_specifiers += "O"; + parameter_list += ", &" + param_name; + extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; + extra_param_check += "|| (" + param_name + "_long == NULL)"; + pexpr_string = "PyLong_AsUnsignedLongLong(" + param_name + "_long)"; + extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; + expected_params += "long"; + + } else if (TypeManager::is_longlong(type)) { + out << "PyObject *" << param_name; + format_specifiers += "O"; + parameter_list += ", &" + param_name; + extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; + extra_param_check += "|| (" + param_name + "_long == NULL)"; + pexpr_string = "PyLong_AsLongLong(" + param_name + "_long)"; + extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; + expected_params += "long"; + } else if (TypeManager::is_integer(type)) { out << "int " << param_name; format_specifiers += "i"; @@ -417,6 +440,26 @@ write_function_instance(ostream &out, int indent_level, << "if (PyArg_ParseTuple(args, \"" << format_specifiers << "\"" << parameter_list << ")) {\n"; + if (!extra_convert.empty()) { + indent(out, indent_level + 3) + << extra_convert << "\n"; + } + + if (!extra_param_check.empty()) { + indent(out, indent_level + 4) + << "if (" << extra_param_check.substr(3) << ") {\n"; + if (!extra_cleanup.empty()) { + indent(out, indent_level + 5) + << extra_cleanup << "\n"; + } + indent(out, indent_level + 6) + << "PyErr_SetString(PyExc_TypeError, \"Invalid parameters.\");\n"; + indent(out, indent_level + 6) + << "return (PyObject *)NULL;\n"; + indent(out, indent_level + 4) + << "}\n"; + } + if (track_interpreter) { indent(out, indent_level + 4) << "in_interpreter = 0;\n"; @@ -438,6 +481,10 @@ write_function_instance(ostream &out, int indent_level, indent(out, indent_level + 4) << "in_interpreter = 1;\n"; } + if (!extra_cleanup.empty()) { + indent(out, indent_level + 3) + << extra_cleanup << "\n"; + } return_expr = manage_return_value(out, indent_level + 4, remap, "return_value"); test_assert(out, indent_level + 4); @@ -451,6 +498,10 @@ write_function_instance(ostream &out, int indent_level, indent(out, indent_level + 4) << "in_interpreter = 1;\n"; } + if (!extra_cleanup.empty()) { + indent(out, indent_level + 3) + << extra_cleanup << "\n"; + } test_assert(out, indent_level + 4); indent(out, indent_level + 4) << "return Py_BuildValue(\"\");\n"; @@ -464,6 +515,10 @@ write_function_instance(ostream &out, int indent_level, indent(out, indent_level + 4) << "in_interpreter = 1;\n"; } + if (!extra_cleanup.empty()) { + indent(out, indent_level + 3) + << extra_cleanup << "\n"; + } return_expr = manage_return_value(out, indent_level + 4, remap, "return_value"); test_assert(out, indent_level + 4); @@ -501,6 +556,14 @@ pack_return_value(ostream &out, int indent_level, << return_expr << ".data(), " << return_expr << ".length());\n"; } + } else if (TypeManager::is_unsigned_longlong(type)) { + indent(out, indent_level) + << "return PyLong_FromUnsignedLongLong(" << return_expr << ");\n"; + + } else if (TypeManager::is_longlong(type)) { + indent(out, indent_level) + << "return PyLong_FromLongLong(" << return_expr << ");\n"; + } else if (TypeManager::is_integer(type)) { indent(out, indent_level) << "return PyInt_FromLong(" << return_expr << ");\n"; diff --git a/dtool/src/interrogate/interfaceMakerPythonSimple.cxx b/dtool/src/interrogate/interfaceMakerPythonSimple.cxx index c3d5f37207..88b1915e0b 100644 --- a/dtool/src/interrogate/interfaceMakerPythonSimple.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonSimple.cxx @@ -242,6 +242,9 @@ write_function_instance(ostream &out, InterfaceMaker::Function *func, string parameter_list; string container; vector_string pexprs; + string extra_convert; + string extra_param_check; + string extra_cleanup; // Make one pass through the parameter list. We will output a // one-line temporary variable definition for each parameter, while @@ -283,6 +286,24 @@ write_function_instance(ostream &out, InterfaceMaker::Function *func, parameter_list += ", &" + param_name; pexpr_string = "(PyObject_IsTrue(" + param_name + ")!=0)"; + } else if (TypeManager::is_unsigned_longlong(type)) { + out << "PyObject *" << param_name; + format_specifiers += "O"; + parameter_list += ", &" + param_name; + extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; + extra_param_check += "|| (" + param_name + "_long == NULL)"; + pexpr_string = "PyLong_AsUnsignedLongLong(" + param_name + "_long)"; + extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; + + } else if (TypeManager::is_longlong(type)) { + out << "PyObject *" << param_name; + format_specifiers += "O"; + parameter_list += ", &" + param_name; + extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; + extra_param_check += "|| (" + param_name + "_long == NULL)"; + pexpr_string = "PyLong_AsLongLong(" + param_name + "_long)"; + extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; + } else if (TypeManager::is_integer(type)) { out << "int " << param_name; format_specifiers += "i"; @@ -326,17 +347,30 @@ write_function_instance(ostream &out, InterfaceMaker::Function *func, out << " if (PyArg_ParseTuple(args, \"" << format_specifiers << "\"" << parameter_list << ")) {\n"; + + if (!extra_convert.empty()) { + out << " " << extra_convert << "\n"; + } + + if (!extra_param_check.empty()) { + out << " if (" << extra_param_check.substr(3) << ") {\n"; + if (!extra_cleanup.empty()) { + out << " " << extra_cleanup << "\n"; + } + out << " PyErr_SetString(PyExc_TypeError, \"Invalid parameters.\");\n" + << " return (PyObject *)NULL;\n" + << " }\n"; + } if (track_interpreter) { out << " in_interpreter = 0;\n"; } - + if (!remap->_void_return && remap->_return_type->new_type_is_atomic_string()) { // Treat strings as a special case. We don't want to format the // return expression. string return_expr = remap->call_function(out, 4, false, container, pexprs); - CPPType *type = remap->_return_type->get_orig_type(); out << " "; type->output_instance(out, "return_value", &parser); @@ -345,6 +379,9 @@ write_function_instance(ostream &out, InterfaceMaker::Function *func, if (track_interpreter) { out << " in_interpreter = 1;\n"; } + if (!extra_cleanup.empty()) { + out << " " << extra_cleanup << "\n"; + } return_expr = manage_return_value(out, 4, remap, "return_value"); test_assert(out, 4); @@ -356,6 +393,9 @@ write_function_instance(ostream &out, InterfaceMaker::Function *func, if (track_interpreter) { out << " in_interpreter = 1;\n"; } + if (!extra_cleanup.empty()) { + out << " " << extra_cleanup << "\n"; + } test_assert(out, 4); out << " return Py_BuildValue(\"\");\n"; @@ -367,6 +407,9 @@ write_function_instance(ostream &out, InterfaceMaker::Function *func, if (track_interpreter) { out << " in_interpreter = 1;\n"; } + if (!extra_cleanup.empty()) { + out << " " << extra_cleanup << "\n"; + } return_expr = manage_return_value(out, 4, remap, "return_value"); test_assert(out, 4); @@ -403,6 +446,14 @@ pack_return_value(ostream &out, int indent_level, << return_expr << ".data(), " << return_expr << ".length());\n"; } + } else if (TypeManager::is_unsigned_longlong(type)) { + indent(out, indent_level) + << "return PyLong_FromUnsignedLongLong(" << return_expr << ");\n"; + + } else if (TypeManager::is_longlong(type)) { + indent(out, indent_level) + << "return PyLong_FromLongLong(" << return_expr << ");\n"; + } else if (TypeManager::is_integer(type)) { indent(out, indent_level) << "return PyInt_FromLong(" << return_expr << ");\n"; diff --git a/dtool/src/interrogate/interrogateBuilder.cxx b/dtool/src/interrogate/interrogateBuilder.cxx index 26bad9eb52..4c7a05cd77 100644 --- a/dtool/src/interrogate/interrogateBuilder.cxx +++ b/dtool/src/interrogate/interrogateBuilder.cxx @@ -1787,7 +1787,11 @@ define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype) { break; case CPPSimpleType::T_int: - itype._atomic_token = AT_int; + if ((cpptype->_flags & CPPSimpleType::F_longlong) != 0) { + itype._atomic_token = AT_longlong; + } else { + itype._atomic_token = AT_int; + } break; case CPPSimpleType::T_float: diff --git a/dtool/src/interrogate/typeManager.cxx b/dtool/src/interrogate/typeManager.cxx index 2ffc29819b..9d3ea2d649 100644 --- a/dtool/src/interrogate/typeManager.cxx +++ b/dtool/src/interrogate/typeManager.cxx @@ -489,6 +489,7 @@ is_bool(CPPType *type) { simple_type->_type == CPPSimpleType::T_bool; } } + break; default: break; @@ -523,6 +524,67 @@ is_integer(CPPType *type) { simple_type->_type == CPPSimpleType::T_int); } } + break; + + default: + break; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: TypeManager::is_unsigned_longlong +// Access: Public, Static +// Description: Returns true if the indicated type is an unsigned +// "long long" type or larger, or at least a 64-bit +// unsigned integer. +//////////////////////////////////////////////////////////////////// +bool TypeManager:: +is_unsigned_longlong(CPPType *type) { + switch (type->get_subtype()) { + case CPPDeclaration::ST_const: + return is_unsigned_longlong(type->as_const_type()->_wrapped_around); + + case CPPDeclaration::ST_simple: + { + CPPSimpleType *simple_type = type->as_simple_type(); + if (simple_type != (CPPSimpleType *)NULL) { + return (simple_type->_type == CPPSimpleType::T_int && + (simple_type->_flags & (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned)) == (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned)); + } + } + break; + + default: + break; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: TypeManager::is_longlong +// Access: Public, Static +// Description: Returns true if the indicated type is the "long long" +// type or larger, or at least a 64-bit integer, whether +// signed or unsigned. +//////////////////////////////////////////////////////////////////// +bool TypeManager:: +is_longlong(CPPType *type) { + switch (type->get_subtype()) { + case CPPDeclaration::ST_const: + return is_longlong(type->as_const_type()->_wrapped_around); + + case CPPDeclaration::ST_simple: + { + CPPSimpleType *simple_type = type->as_simple_type(); + if (simple_type != (CPPSimpleType *)NULL) { + return (simple_type->_type == CPPSimpleType::T_int && + (simple_type->_flags & CPPSimpleType::F_longlong) != 0); + } + } + break; default: break; @@ -553,6 +615,7 @@ is_float(CPPType *type) { simple_type->_type == CPPSimpleType::T_double); } } + break; default: break; @@ -609,10 +672,13 @@ is_reference_count(CPPType *type) { } } } + break; default: - return false; + break; } + + return false; } //////////////////////////////////////////////////////////////////// diff --git a/dtool/src/interrogate/typeManager.h b/dtool/src/interrogate/typeManager.h index 79a0438bfa..ecdc303c41 100644 --- a/dtool/src/interrogate/typeManager.h +++ b/dtool/src/interrogate/typeManager.h @@ -70,6 +70,8 @@ public: static bool is_const_ref_to_basic_string_char(CPPType *type); static bool is_bool(CPPType *type); static bool is_integer(CPPType *type); + static bool is_unsigned_longlong(CPPType *type); + static bool is_longlong(CPPType *type); static bool is_float(CPPType *type); static bool is_void(CPPType *type); static bool is_reference_count(CPPType *type); diff --git a/dtool/src/interrogatedb/interrogate_interface.h b/dtool/src/interrogatedb/interrogate_interface.h index 73426ae9d6..d733d5d054 100644 --- a/dtool/src/interrogatedb/interrogate_interface.h +++ b/dtool/src/interrogatedb/interrogate_interface.h @@ -85,7 +85,9 @@ enum AtomicToken { // convention wrappers, atomic string means (const char *); for // other calling convention wrappers, atomic string means whatever // the native string representation is. - AT_string = 7 + AT_string = 7, + + AT_longlong = 8 }; EXPCL_DTOOLCONFIG void interrogate_add_search_directory(const char *dirname);