aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/python/PythonSwig.cpp.template
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/python/PythonSwig.cpp.template')
-rw-r--r--src/interfaces/python/PythonSwig.cpp.template840
1 files changed, 840 insertions, 0 deletions
diff --git a/src/interfaces/python/PythonSwig.cpp.template b/src/interfaces/python/PythonSwig.cpp.template
new file mode 100644
index 0000000000..0adba508e5
--- /dev/null
+++ b/src/interfaces/python/PythonSwig.cpp.template
@@ -0,0 +1,840 @@
+<%
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+%>
+<%
+import Helper
+import SwigTypeParser
+import PythonTools
+
+import groovy.xml.XmlUtil
+import groovy.text.SimpleTemplateEngine
+import java.util.regex.Pattern
+
+/**
+ * All of the method nodes and all of the class nodes are used several
+ * times over, so they are pulled out once here.
+ */
+
+// ---------------------------------------------------------
+// initialize the SwigTypeParser with the module's typetables
+module.findAll( { it.name() == 'typetab' } ).each { SwigTypeParser.appendTypeTable(it) }
+// ---------------------------------------------------------
+
+// ---------------------------------------------------------
+// Flatten out all of the method/function nodes, whether inside
+// classes or not, into 'methods'
+List methods = module.depthFirst().findAll { it.name() == 'function' || it.name() == 'constructor' || it.name() == 'destructor' }
+// ---------------------------------------------------------
+
+// ---------------------------------------------------------
+// Flatten out all of the class nodes into 'classes'
+List classes = module.depthFirst().findAll { it.name() == 'class' }
+// ---------------------------------------------------------
+
+// ---------------------------------------------------------
+// Initialize the Helper with the type conversions
+Helper.setup(this,classes,
+ /**
+ * This is meant to contain mini-templates for converting the return type
+ * of the native call to be returned to the python caller.
+ */
+ [ 'void' : 'Py_INCREF(Py_None);\n ${result} = Py_None;',
+ 'long': '${result} = PyInt_FromLong(${api});',
+ 'unsigned long': '${result} = PyInt_FromLong(${api});',
+ 'bool': '${result} = Py_BuildValue((char*)"b", ${api});',
+ 'long long': '${result} = Py_BuildValue((char*)"L", ${api});',
+ 'int': '${result} = Py_BuildValue((char*)"i", ${api});',
+ 'double': '${result} = PyFloat_FromDouble(${api});',
+ 'float': '${result} = Py_BuildValue((char*)"f", ${api});',
+ 'std::string' : new File('typemaps/python.string.outtm'),
+ 'p.q(const).char' : '${result} = PyString_FromString(${api});',
+ (Pattern.compile('''(p.){0,1}XbmcCommons::Buffer''')) : new File('typemaps/python.buffer.outtm'),
+ (Pattern.compile('''boost::shared_ptr<\\(.*\\)>''')) : new File('typemaps/python.boost_shared_ptr.outtm'),
+ (Pattern.compile('''(p.){0,1}std::vector<\\(.*\\)>''')) : new File('typemaps/python.vector.outtm'),
+ (Pattern.compile('''(p.){0,1}Tuple<\\(.*\\)>''')) : new File('typemaps/python.Tuple.outtm'),
+ (Pattern.compile('''(p.){0,1}Alternative<\\(.*\\)>''')) : new File('typemaps/python.Alternative.outtm')
+ ], '${result} = makePythonInstance(${api},true);',
+ /**
+ * This is meant to contain mini-templates for converting the parameter types
+ * of the native call to be converted from the python types provided by the caller.
+ *
+ * Note: if the type can be handled by PythonTools.ltypeToFormatChar then it wont
+ * appear here as it gets converted directly within the PyArg_ParseTupleAndKeywords
+ * call.
+ */
+ [
+ 'std::string' : 'if (${slarg}) PyXBMCGetUnicodeString(${api},${slarg},false,"${api}","${method.@name}");',
+ (Pattern.compile('''(p.){0,1}std::vector<\\(.*\\)>''')) : new File('typemaps/python.vector.intm'),
+ (Pattern.compile('''(p.){0,1}Tuple(3){0,1}<\\(.*\\)>''')) : new File('typemaps/python.Tuple.intm'),
+ (Pattern.compile('''(p.){0,1}Alternative<\\(.*\\)>''')) : new File('typemaps/python.Alternative.intm'),
+ (Pattern.compile('''(r.){0,1}XbmcCommons::Buffer''')) : new File('typemaps/python.buffer.intm'),
+ (Pattern.compile('''(p.){0,1}std::map<\\(.*\\)>''')) : new File('typemaps/python.map.intm'),
+ (Pattern.compile('''(r.){0,1}XBMCAddon::Dictionary<\\(.*\\)>''')) : new File('typemaps/python.dict.intm'),
+ 'bool' : '${api} = (PyInt_AsLong(${slarg}) == 0L ? false : true);',
+ 'long' : '${api} = PyInt_AsLong(${slarg});',
+ 'unsigned long' : '${api} = PyLong_AsUnsignedLong(${slarg});',
+ 'long long' : '${api} = PyLong_AsLongLong(${slarg});',
+ 'unsigned long long' : '${api} = PyLong_AsUnsignedLongLong(${slarg});',
+ 'int' : '${api} = (int)PyInt_AsLong(${slarg});',
+ 'double' : '${api} = PyFloat_AsDouble(${slarg});',
+ 'float' : '${api} = (float)PyFloat_AsDouble(${slarg});',
+ 'XBMCAddon::StringOrInt' : 'if (${slarg}) PyXBMCGetUnicodeString(${api},${slarg},PyInt_Check(${slarg}) || PyLong_Check(${slarg}) || PyFloat_Check(${slarg}),"${api}","${method.@name}");'
+ ], '${api} = (${swigTypeParser.SwigType_str(ltype)})retrieveApiInstance(${slarg},"${ltype}","${helper.findNamespace(method)}","${helper.callingName(method)}");')
+// ---------------------------------------------------------
+
+/*******************************************************************************/
+/**
+ * The doMethod will actually write out the CPython method call for
+ * the method/function represented by the provided Node ('method').
+ */
+void doMethod(Node method, MethodType methodType)
+{
+ boolean isOperator = method.@name.startsWith("operator ")
+ boolean doAsMappingIndex = false
+
+ if (isOperator)
+ {
+ if("[]" == method.@name.substring(9))
+ doAsMappingIndex = true
+ else
+ return;
+ }
+
+ boolean constructor = methodType == MethodType.constructor
+
+ // if we're a constructor, but we're private, then we're outta here
+ if (constructor && method.@access != null && method.@access != "public")
+ return
+
+ boolean destructor = methodType == MethodType.destructor
+ List params = method?.parm
+ int numParams = params?.size()
+ String clazz = Helper.findFullClassName(method)
+ String returns = constructor ? 'p.' + clazz : (destructor ? 'void' : Helper.getReturnSwigType(method))
+ Node classnode = Helper.findClassNode(method)
+ String classNameAsVariable = clazz == null ? null : PythonTools.getClassNameAsVariable(classnode)
+ boolean useKeywordParsing = !('true' == classnode?.@feature_python_nokwds || 'true' == method?.@feature_python_nokwds)
+
+ // do the docs
+ if (!constructor && !destructor)
+ {
+ if (Helper.hasDoc(method))
+ {
+%>
+ PyDoc_STRVAR(${PythonTools.getPyMethodName(method,methodType)}__doc__,
+ ${PythonTools.makeDocString(method.doc[0])});
+<% }
+ }
+%>
+ static <% if(methodType == MethodType.destructor) { %>void<% } else { %>PyObject*<% } %> ${module.@name}_${PythonTools.getPyMethodName(method,methodType)} (<%= ((clazz == null) ? "PyObject" :
+ (constructor ? "PyTypeObject" : 'PyHolder')) %>* ${constructor ? 'pytype' : 'self'} <%
+ if (doAsMappingIndex) { %>, PyObject* py${params[0].@name}<% }
+ else if (methodType != MethodType.destructor) { %> , PyObject *args, PyObject *kwds <%} %> )
+ {
+ XBMC_TRACE;
+<% if (numParams > 0)
+ {
+ if (useKeywordParsing && !doAsMappingIndex)
+ { %>
+ static const char *keywords[] = {<%
+ params.each { %>
+ "${it.@name}",<% } %>
+ NULL};
+<% }
+ params.each {
+%>
+ ${SwigTypeParser.SwigType_str(SwigTypeParser.convertTypeToLTypeForParam(it.@type))} ${it.@name} ${it.@value != null ? ' = ' + it.@value : ''};<%
+ if (!PythonTools.parameterCanBeUsedDirectly(it))
+ { %>
+ PyObject* py${it.@name} = NULL;<%
+ }
+ }
+ if (!doAsMappingIndex)
+ { %>
+ if (!${useKeywordParsing ? 'PyArg_ParseTupleAndKeywords' : 'PyArg_ParseTuple'}(
+ args,
+ <% if (useKeywordParsing) { %>kwds,<% } %>
+ (char*)"<%= PythonTools.makeFormatStringFromParameters(method) %>",
+ <% if (useKeywordParsing) { %>(char**)keywords,<% } %><% params.eachWithIndex { param,i -> %>
+ &${PythonTools.parameterCanBeUsedDirectly(param) ? '' : 'py'}${param.@name}${i < params.size() - 1 ? "," : ""}<% } %>
+ ))
+ {
+ return NULL;
+ }
+
+<% }
+ }
+ // now actually invoke the method
+ if (returns != "void") { %> ${SwigTypeParser.SwigType_lstr(returns)} apiResult;<% }
+%>
+ try
+ {
+<%
+ // now do the input converstion if any are necessary
+ params.findAll({ !PythonTools.parameterCanBeUsedDirectly(it) || doAsMappingIndex }).each { %> ${Helper.getInConversion(it.@type, it.@name, 'py' + it.@name, method)} <% println() }
+%>
+<%
+ // check to see if this method is a call to a virtual function on a director class.
+ boolean isDirectorCall = Helper.isDirector(method)
+ if (isDirectorCall)
+ {
+%> // This is a director call comming from python so it explcitly calls the base class method.
+<%
+ }
+ // now do the method call itself
+ if (!destructor) {
+ if (constructor || !clazz) { %> XBMCAddon::SetLanguageHookGuard slhg(XBMCAddon::Python::PythonLanguageHook::GetIfExists(PyThreadState_Get()->interp).get());<% println() }
+%> <%
+ if (returns != "void") { %>apiResult = (${SwigTypeParser.SwigType_lstr(returns)})<% }
+ if (clazz && !constructor) {
+ %>((${clazz}*)retrieveApiInstance((PyObject*)self,&Ty${classNameAsVariable}_Type,"${Helper.callingName(method)}","${clazz}"))-> <%
+ }
+ if (constructor && classnode.@feature_director) {
+ %>(&(Ty${classNameAsVariable}_Type.pythonType) != pytype) ? new ${classNameAsVariable}_Director(<% params.eachWithIndex { param, i -> %> ${param.@name}${i < params.size() - 1 ? "," : ""} <% } %>) : <% }
+
+ // Here is the actual call ... if this is a Director we need to do an upCall (from Python)
+ if (isDirectorCall){ %>${clazz}::<% }
+ %>${Helper.callingName(method)}( <% params.eachWithIndex { param, i -> %> ${param.@name}${i < params.size() - 1 ? "," : ""} <% } %> );
+<%
+ if (constructor) { %> prepareForReturn(apiResult);<% }
+ } // close the 'if method is not a destructor'
+ else { // it is a destructor
+%>
+ ${clazz}* theObj = (${clazz}*)retrieveApiInstance((PyObject*)self,&Ty${classNameAsVariable}_Type,"~${Helper.callingName(method)}","${clazz}");
+ cleanForDealloc(theObj);
+<%
+ }
+%>
+ }
+ catch (const XBMCAddon::WrongTypeException& e)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: %s",e.GetMessage());
+ PyErr_SetString(PyExc_TypeError, e.GetMessage()); <%
+ if (!destructor) { %>
+ return NULL; <%
+ } %>
+ }
+ catch (const XbmcCommons::Exception& e)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: %s",e.GetMessage());
+ PyErr_SetString(PyExc_RuntimeError, e.GetMessage()); <%
+ if (!destructor) { %>
+ return NULL; <%
+ } %>
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: Unknown exception thrown from the call \"${Helper.callingName(method)}\"");
+ PyErr_SetString(PyExc_RuntimeError, "Unknown exception thrown from the call \"${Helper.callingName(method)}\""); <%
+ if (!destructor) { %>
+ return NULL; <%
+ } %>
+ }
+<%
+ if (!destructor) { %>
+ PyObject* result = Py_None;
+
+ // transform the result
+<%
+ if (constructor) {
+ %> result = makePythonInstance(apiResult,pytype,false);<%
+ }
+ else {
+%> ${Helper.getOutConversion(returns,'result',method)}<%
+ }
+ if (constructor && method.@feature_director) { %>
+ if (&(Ty${classNameAsVariable}_Type.pythonType) != pytype)
+ ((${classNameAsVariable}_Director*)apiResult)->setPyObjectForDirector(result);<%
+ }
+ %>
+
+ return result; <% }
+ else { %>
+ self->ob_type->tp_free((PyObject*)self);
+ <%
+ }
+ %>
+ } <%
+}
+/*******************************************************************************/
+
+/**
+ * This method writes out the instance of a TypeInfo (which includes
+ * The PyTypeObject as a member) for the class node provided.
+ *
+ * If classNameAsVariable is not null then the class name as a
+ * variable will be appended to it.
+ */
+void doClassTypeInfo(Node clazz, List classNameAsVariables = null)
+{
+ String classNameAsVariable = PythonTools.getClassNameAsVariable(clazz)
+ String fullClassName = Helper.findFullClassName(clazz)
+ classNameAsVariables?.add(classNameAsVariable)
+%>
+ //=========================================================================
+ // These variables will hold the Python Type information for ${fullClassName}
+ TypeInfo Ty${classNameAsVariable}_Type(typeid(${fullClassName}));<%
+%>
+ //=========================================================================
+<%
+}
+
+/**
+ * This method will take the name of an API class from another module and
+ * create an external reference to its TypeInfo instance.
+ */
+void doExternClassTypeInfo(String knownType)
+{
+ String classNameAsVariable = knownType.replaceAll('::','_')
+%>
+ //=========================================================================
+ // These variables define the type ${knownType} from another module
+ extern TypeInfo Ty${classNameAsVariable}_Type;
+ //=========================================================================
+<%
+}
+
+/*******************************************************************************/
+/**
+ * This method takes the class node and outputs all of the python meta-data
+ * and class oddities (like comparators, as_mapping, etc.). These include:
+ *
+ * 1) comparator *_cmp python method as long as there's an operator==, an
+ * operator>, AND an operator<.
+ * 2) it will create a python "as_mapping" method as long as there's both
+ * an operator[], AND a .size() method on the class.
+ * 3) it will handle the explicitly defined rich compare (_rcmp) if the
+ * feature is included in the .i file using %feature("python:rcmp")
+ * 4) The array of PyMethodDefs for the class definition
+ * 5) It will handle public fields as if the were python properties by:
+ * a) Creating a get/set_member if there are read/write properties.
+ * b) Creating only a get if there are only read-only properties.
+ * 6) It will write the init[Classname] method for the class which will
+ * initialize the TypeInfo and PyTypeObject structs.
+ *
+ * If initTypeCalls is not null then the method name for the generated init
+ * method (see #6 above) will be appended to it.
+ */
+void doClassMethodInfo(Node clazz, List initTypeCalls)
+{
+ String classNameAsVariable = PythonTools.getClassNameAsVariable(clazz)
+ String fullClassName = Helper.findFullClassName(clazz)
+ String initTypeCall = "initPy${classNameAsVariable}_Type"
+ initTypeCalls?.add(initTypeCall)
+
+ // see if we have any valid (or invalid) operators
+ boolean doComparator = false
+ boolean doAsMapping = false
+ boolean hasEquivalenceOp = false
+ boolean hasLtOp = false
+ boolean hasGtOp = false
+ Node indexOp = null
+ Node sizeNode = null
+
+ List normalMethods = clazz.function.findAll { !it.@name.startsWith("operator ") }
+ List operators = clazz.function.findAll { it.@name.startsWith("operator ") }
+ List properties = clazz.variable.findAll { it.@access != null && it.@access == "public" }
+ List properties_set = properties.findAll { it.@feature_immutable == null || it.@feature_immutable == 0 }
+
+ operators.each {
+ // we have an operator. The only one we can handle is ==
+ if (it.@name.substring(9).startsWith("=="))
+ hasEquivalenceOp = true
+ else if (it.@name.substring(9) == "<")
+ hasLtOp = true
+ else if (it.@name.substring(9) == ">")
+ hasGtOp = true
+ else if (it.@name.substring(9) == "[]")
+ indexOp = it
+ else
+ System.err.println ("Warning: class ${fullClassName} has an operator \"${it.@name}\" that is being ignored.");
+ }
+
+ if (hasGtOp || hasLtOp || hasEquivalenceOp)
+ {
+ if (!(hasLtOp && hasGtOp && hasEquivalenceOp))
+ System.err.println ("Warning: class ${fullClassName} has an inconsistent operator set. To get a comparator you must implement all 3 operators >,<,==.")
+ else
+ doComparator = true
+ }
+
+ if (indexOp)
+ {
+ sizeNode = clazz.function.find { it.@name == "size" }
+ if (sizeNode)
+ doAsMapping = true
+ else
+ System.err.println ("Warning: class ${fullClassName} has an inconsistent operator set. To get a as_mapping you must implement 'size' as well as operator[]")
+ }
+
+ if (doComparator){
+%>
+ static int ${module.@name}_${classNameAsVariable}_cmp(PyObject* obj1, PyObject* obj2)
+ {
+ return PythonCompare<${fullClassName}>::compare(obj1,obj2,"p.${fullClassName}","${Helper.findNamespace(clazz)}","compare on ${fullClassName}");
+ }
+<%
+ }
+
+ if (doAsMapping)
+ {
+%>
+ static Py_ssize_t ${module.@name}_${classNameAsVariable}_size_(PyObject* self)
+ {
+ return (Py_ssize_t)((${fullClassName}*)retrieveApiInstance(self,&Ty${classNameAsVariable}_Type,"${Helper.callingName(indexOp)}","${fullClassName}"))-> size();
+ }
+
+ //=========================================================================
+ // tp_as_mapping struct for ${fullClassName}
+ //=========================================================================
+ PyMappingMethods ${module.@name}_${classNameAsVariable}_as_mapping = {
+ ${module.@name}_${classNameAsVariable}_size_, /* inquiry mp_length; __len__ */
+ (PyCFunction)${module.@name}_${PythonTools.getPyMethodName(indexOp,MethodType.method)}, /* binaryfunc mp_subscript __getitem__ */
+ 0, /* objargproc mp_ass_subscript; __setitem__ */
+ };
+<%
+ }
+
+ if (clazz.@feature_python_rcmp)
+ { %>
+ static PyObject* ${module.@name}_${classNameAsVariable}_rcmp(PyObject* obj1, PyObject *obj2, int method)
+ ${Helper.unescape(clazz.@feature_python_rcmp)}
+<%
+ }
+%>
+ //=========================================================================
+ // This section contains the initialization for the
+ // Python extention for the Api class ${fullClassName}
+ //=========================================================================
+ // All of the methods on this class
+ static PyMethodDef ${classNameAsVariable}_methods[] = { <%
+ normalMethods.each { %>
+ {(char*)"${it.@sym_name}", (PyCFunction)${module.@name}_${PythonTools.getPyMethodName(it,MethodType.method)}, METH_VARARGS|METH_KEYWORDS, ${Helper.hasDoc(it) ? PythonTools.getPyMethodName(it,MethodType.method) + '__doc__' : 'NULL'} }, <% }
+
+ // now do all of the explcit feature:python:method's that may be in this class
+ List tmpl = []
+ tmpl.addAll(clazz.attributes().keySet())
+ List newMethodKeys = tmpl.findAll { it.startsWith('feature_python_method_') }
+ newMethodKeys.each { key ->
+ String featureEntry = clazz.attribute(key)
+ String methodName = key.substring('feature_python_method_'.length()) %>
+ {(char*)"${methodName}", (PyCFunction)${module.@name}_${PythonTools.getClassNameAsVariable(clazz)}_${methodName}, METH_VARARGS|METH_KEYWORDS, NULL},
+<%
+ }
+%>
+ {NULL, NULL, 0, NULL}
+ };
+
+<%
+ if (properties.size() > 0) {
+%> static PyObject* ${classNameAsVariable}_getMember(PyHolder *self, void *name)
+ {
+ if (self == NULL)
+ return NULL;
+<%
+ String clazzName = Helper.findFullClassName(properties[0])
+%>
+ try
+ {
+ ${clazzName}* theObj = (${clazzName}*)retrieveApiInstance((PyObject*)self, &Ty${classNameAsVariable}_Type, "${classNameAsVariable}_getMember()", "${clazzName}");
+
+ PyObject* result = NULL;
+ <%
+ properties.each {
+%> if (strcmp((char*)name, "${it.@sym_name}") == 0)
+ {
+ ${SwigTypeParser.SwigType_lstr(it.@type)} apiResult = (${SwigTypeParser.SwigType_lstr(it.@type)})theObj->${it.@sym_name};
+ ${Helper.getOutConversion(it.@type, 'result', it)}
+ }
+ else<%
+ } %>
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return result;
+ }
+ catch (const XBMCAddon::WrongTypeException& e)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: %s",e.GetMessage());
+ PyErr_SetString(PyExc_TypeError, e.GetMessage());
+ return NULL;
+ }
+ catch (const XbmcCommons::Exception& e)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: %s",e.GetMessage());
+ PyErr_SetString(PyExc_RuntimeError, e.GetMessage());
+ return NULL;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: Unknown exception thrown from the call \"${classNameAsVariable}_getMember()\"");
+ PyErr_SetString(PyExc_RuntimeError, "Unknown exception thrown from the call \"${classNameAsVariable}_getMember()\"");
+ return NULL;
+ }
+
+ return NULL;
+ }
+
+<%
+ if (properties_set.size() > 0) {
+%> int ${classNameAsVariable}_setMember(PyHolder *self, PyObject *value, void *name)
+ {
+ if (self == NULL)
+ return -1;
+
+ ${clazzName}* theObj = NULL;
+ try
+ {
+ theObj = (${clazzName}*)retrieveApiInstance((PyObject*)self, &Ty${classNameAsVariable}_Type, "${classNameAsVariable}_getMember()", "${clazzName}");
+ }
+ catch (const XBMCAddon::WrongTypeException& e)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: %s",e.GetMessage());
+ PyErr_SetString(PyExc_TypeError, e.GetMessage());
+ return NULL;
+ }
+ catch (const XbmcCommons::Exception& e)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: %s",e.GetMessage());
+ PyErr_SetString(PyExc_RuntimeError, e.GetMessage());
+ return NULL;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR,"EXCEPTION: Unknown exception thrown from the call \"${classNameAsVariable}_getMember()\"");
+ PyErr_SetString(PyExc_RuntimeError, "Unknown exception thrown from the call \"${classNameAsVariable}_getMember()\"");
+ return NULL;
+ }
+
+<%
+ properties_set.each {
+%> if (strcmp((char*)name, "${it.@sym_name}") == 0)
+ {
+ ${SwigTypeParser.SwigType_lstr(it.@type)} tmp;
+ ${Helper.getInConversion(it.@type, 'tmp', 'value', it)}
+ if (PyErr_Occurred())
+ throw PythonBindings::PythonToCppException();
+
+ theObj->${it.@sym_name} = tmp;
+ }
+ else<%
+ } %>
+ return -1;
+
+ return 0;
+ } <%
+ }
+%>
+
+ // All of the methods on this class
+ static PyGetSetDef ${classNameAsVariable}_getsets[] = { <%
+ properties.each { %>
+ {(char*)"${it.@sym_name}", (getter)${classNameAsVariable}_getMember, ${(it.@feature_immutable == null || it.@feature_immutable == 0) ? '(setter)' + classNameAsVariable + '_setMember' : 'NULL'}, (char*)${Helper.hasDoc(it) ? PythonTools.makeDocString(it.doc[0]) : 'NULL'}, (char*)"${it.@sym_name}" }, <% }
+%>
+ {NULL}
+ };
+<%
+ } %>
+
+ // This method initializes the above mentioned Python Type structure
+ static void ${initTypeCall}()
+ {
+<%
+ if (Helper.hasDoc(clazz))
+ {
+%>
+ PyDoc_STRVAR(${classNameAsVariable}__doc__,
+ ${PythonTools.makeDocString(clazz.doc[0])}
+ );
+<% } %>
+
+ PyTypeObject& pythonType = Ty${classNameAsVariable}_Type.pythonType;
+ pythonType.tp_name = (char*)"${module.@name}.${clazz.@sym_name}";
+ pythonType.tp_basicsize = sizeof(PyHolder);
+ pythonType.tp_dealloc = (destructor)${module.@name}_${classNameAsVariable}_Dealloc; <%
+ if (doComparator) { %>
+ pythonType.tp_compare=${module.@name}_${classNameAsVariable}_cmp;<%
+ }
+ if (clazz.@feature_python_rcmp) { %>
+ pythonType.tp_richcompare=(richcmpfunc)${module.@name}_${classNameAsVariable}_rcmp;<%
+ } %>
+
+ pythonType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
+ pythonType.tp_doc = ${Helper.hasDoc(clazz) ? (classNameAsVariable + '__doc__') : 'NULL' };
+ pythonType.tp_methods = ${classNameAsVariable}_methods; <%
+ if (properties.size() > 0) { %>
+ pythonType.tp_getset = ${classNameAsVariable}_getsets;
+<%
+ }
+ if (doAsMapping) { %>
+ pythonType.tp_as_mapping = &${module.@name}_${classNameAsVariable}_as_mapping;
+<% }
+ Node baseclass = PythonTools.findValidBaseClass(clazz, module)
+
+%>
+ pythonType.tp_base = ${baseclass ? ('&(Ty' + PythonTools.getClassNameAsVariable(baseclass) + '_Type.pythonType)') : "NULL"};
+ pythonType.tp_new = <% Helper.hasHiddenConstructor(clazz) ? print('NULL') : print("${module.@name}_${classNameAsVariable}_New") %>;
+
+ Ty${classNameAsVariable}_Type.swigType="p.${fullClassName}";<%
+ if (baseclass) { %>
+ Ty${classNameAsVariable}_Type.parentType=&Ty${PythonTools.getClassNameAsVariable(baseclass)}_Type;
+<%}
+
+ if (!Helper.hasHiddenConstructor(clazz)) { %>
+ registerAddonClassTypeInformation(&Ty${classNameAsVariable}_Type);
+<%} %>
+ }
+ //=========================================================================
+<%
+}
+/*******************************************************************************/
+
+
+List getAllVirtualMethods(Node clazz)
+{
+ List ret = []
+ ret.addAll(clazz.findAll({ it.name() == 'function' && it.@storage && it.@storage == 'virtual' }))
+ if (clazz.baselist) {
+ if (clazz.baselist[0].base) clazz.baselist[0].base.each {
+ Node baseclassnode = Helper.findClassNodeByName(module,it.@name,clazz)
+ if (baseclassnode && baseclassnode.@feature_director) ret.addAll(getAllVirtualMethods(baseclassnode))
+ }
+ }
+ return ret;
+}
+
+%>
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+// ************************************************************************
+// This file was generated by xbmc compile process. DO NOT EDIT!!
+// It was created by running the code generator on the spec file for
+// the module "${module.@name}" on the template file PythonSwig.template.cpp
+// ************************************************************************
+
+<%
+Helper.getInsertNodes(module, 'begin').each { %>${Helper.unescape(it)}<% }
+%>
+
+#include <Python.h>
+#include <string>
+#include "interfaces/python/LanguageHook.h"
+#include "interfaces/python/swig.h"
+#include "interfaces/python/PyContext.h"
+
+<%
+Helper.getInsertNodes(module, 'header').each { %>${Helper.unescape(it)}<% }
+%>
+
+namespace PythonBindings
+{
+<%
+ // initTypeCalls is the
+ List initTypeCalls = []
+ List classNameAsVariables = []
+
+ classes.each { clazz -> doClassTypeInfo(clazz, classNameAsVariables) }
+
+ // make sure known api types are declared as externs
+
+ // first, find all of the declared known api types
+ Set<String> knownApiTypes = new HashSet<String>()
+ module.depthFirst().each
+ {
+ String attr = it.attribute('feature_knownapitypes')
+ if (attr != null)
+ {
+ attr.trim().split(',').each { knownApiTypes.add(it) }
+ }
+ }
+
+ // now declare an extern for each one
+ knownApiTypes.each { doExternClassTypeInfo(it) }
+
+%>
+
+<%
+//=========================================================================
+// Do the directors. For every class that can be extended in python, we
+// need to create a Director instance with bridging calls. This chunk of
+// code will generate those classes.
+ classes.findAll({ it.@feature_director != null }).each { clazz ->
+ // find the constructor for this class
+ constructor = clazz.constructor[0]
+%>
+ //=========================================================================
+ // This class is the Director for ${Helper.findFullClassName(clazz)}.
+ // It provides the "reverse bridge" from C++ to Python to support
+ // cross-language polymorphism.
+ //=========================================================================
+ class ${PythonTools.getClassNameAsVariable(clazz)}_Director : public Director, public ${clazz.@name}
+ {
+ public:
+<%
+ if (constructor)
+ {%>
+ inline ${PythonTools.getClassNameAsVariable(clazz)}_Director(<%
+ List params = constructor?.parm
+ params.eachWithIndex { param, i -> %>${SwigTypeParser.SwigType_str(param.@type)} ${param.@name}${i < params.size() - 1 ? "," : ""} <% }
+ %>) : ${Helper.findFullClassName(constructor)}(<%
+ params.eachWithIndex { param, i -> %> ${param.@name}${i < params.size() - 1 ? "," : ""} <% } %>) { } <%
+ }
+%>
+<%
+ getAllVirtualMethods(clazz).each
+ { %>
+ virtual ${SwigTypeParser.SwigType_str(Helper.getReturnSwigType(it))} ${Helper.callingName(it)}( <%
+ List params = it?.parm
+ String paramFormatStr = ''
+ params.each { paramFormatStr += 'O' }
+ params.eachWithIndex { param, i -> %> ${SwigTypeParser.SwigType_str(param.@type)} ${param.@name}${i < params.size() - 1 ? "," : ""} <% }
+ %> )
+ { <%
+ params.each
+ { param ->
+ %>
+ PyObject* py${param.@name} = NULL;
+ ${Helper.getOutConversion(param.@type,'result',it,['result' : 'py' + param.@name, 'api' : param.@name])}<%
+ }
+%>
+ XBMCAddon::Python::PyContext pyContext;
+ PyObject_CallMethod(self,(char*)"${Helper.callingName(it)}",(char*)"(${paramFormatStr})"<%
+ params.each {
+ %>, py${it.@name} <%
+ }
+ %>);
+ if (PyErr_Occurred())
+ throw PythonBindings::PythonToCppException();
+ }
+<% }
+
+%>
+ };
+<%
+ }
+//=========================================================================
+
+ // types used as method parameter or return values need to be declared
+ // as extern if they are unknown types.
+ methods.each { if (it.name() != 'destructor') { doMethod(it, (it.name() == 'constructor' ? MethodType.constructor : MethodType.method)); println(); } }
+ classes.each { clazz -> doMethod(clazz, MethodType.destructor) }
+
+ // now find any methods that have been added explicitly
+ classes.each { node ->
+ List tmpl = []
+ tmpl.addAll(node.attributes().keySet())
+ List newMethodKeys = tmpl.findAll { it.startsWith('feature_python_method_') }
+ newMethodKeys.each { key ->
+ String featureEntry = node.attribute(key)
+ String methodName = key.substring('feature_python_method_'.length()) %>
+ static PyObject* ${module.@name}_${PythonTools.getClassNameAsVariable(node)}_${methodName}(PyObject* self, PyObject *args, PyObject *kwds)
+ ${Helper.unescape(featureEntry)}
+<%
+ }
+ }
+
+ classes.each { clazz -> doClassMethodInfo(clazz, initTypeCalls) }
+
+%>
+
+ static PyMethodDef ${module.@name}_methods[] = { <%
+ module.depthFirst().findAll({ it.name() == 'function' && Helper.parents(it, { Node lnode -> lnode.name() == 'class'}).size() == 0 }).each { %>
+ {(char*)"${it.@sym_name}", (PyCFunction)${module.@name}_${PythonTools.getPyMethodName(it,MethodType.method)}, METH_VARARGS|METH_KEYWORDS, ${Helper.hasDoc(it) ? PythonTools.getPyMethodName(it,MethodType.method) + '__doc__' : 'NULL'} }, <% }
+%>
+ {NULL, NULL, 0, NULL}
+ };
+
+ // This is the call that will call all of the other initializes
+ // for all of the classes in this module
+ static void initTypes()
+ {
+ static bool typesAlreadyInitialized = false;
+ if (!typesAlreadyInitialized)
+ {
+ typesAlreadyInitialized = true;
+<%
+ initTypeCalls.each { %>
+ ${it}();<%
+ }
+
+ classNameAsVariables.each { %>
+ if (PyType_Ready(&(Ty${it}_Type.pythonType)) < 0)
+ return;<%
+ }%>
+ }
+ }
+
+ void initModule_${module.@name}()
+ {
+ initTypes();
+
+ // init general ${module.@name} modules
+ PyObject* module;
+
+<% classNameAsVariables.each { %>
+ Py_INCREF(&(Ty${it}_Type.pythonType));<%
+ }%>
+
+ module = Py_InitModule((char*)"${module.@name}", ${module.@name}_methods);
+ if (module == NULL) return;
+
+<% classes.each { clazz -> %>
+ PyModule_AddObject(module, (char*)"${clazz.@sym_name}", (PyObject*)(&(Ty${PythonTools.getClassNameAsVariable(clazz)}_Type.pythonType)));<%
+ }%>
+
+ // constants
+ PyModule_AddStringConstant(module, (char*)"__author__", (char*)"Team XBMC <http://xbmc.org>");
+ PyModule_AddStringConstant(module, (char*)"__date__", (char*)"${new Date().toString()}");
+ PyModule_AddStringConstant(module, (char*)"__version__", (char*)"2.19.0");
+ PyModule_AddStringConstant(module, (char*)"__credits__", (char*)"Team XBMC");
+ PyModule_AddStringConstant(module, (char*)"__platform__", (char*)"ALL");
+
+ // need to handle constants
+<% module.depthFirst().findAll( { it.name() == 'constant'} ).each {
+ String pyCall =
+ (it.@type == 'int' || it.@type == 'long' || it.@type == 'unsigned int' || it.@type == 'unsigned long' || it.@type == 'bool') ?
+ 'PyModule_AddIntConstant' : 'PyModule_AddStringConstant' %>
+ ${pyCall}(module,"${it.@sym_name}",${it.@value}); <%
+ } %>
+ }
+
+} // end PythonBindings namespace for python type definitions