+ rtype, method=self.parse_param(ret)
+
+ params=[]
+ for p in paramlist_re.split(param):
+ params.append( self.parse_param(p) )
+
+ if len(params) == 1 and params[0][0] == 'void':
+ # Empty parameter list
+ params=[]
+
+ if list(p for p in params if not p[1]):
+ # Empty parameter names. Have to poke into comment.
+ names=comment_re.findall(comment)
+ if len(names) < len(params):
+ # Bad description: all parameters are not specified.
+ # Generate default parameter names
+ badnames=[ "param%d" % i for i in xrange(len(params)) ]
+ # Put in the existing ones
+ for (i, p) in enumerate(names):
+ badnames[i]=names[i]
+ names=badnames
+ print "### Error ###"
+ print "### Cannot get parameter names from comment for %s: %s" % (method, comment.replace("\n", ' '))
+ # Note: this was previously
+ # raise Exception("Cannot get parameter names from comment for %s: %s" % (method, comment))
+ # but it prevented code generation for a minor detail (some bad descriptions).
+ params=[ (p[0], names[i]) for (i, p) in enumerate(params) ]
+
+ # Transform Doxygen syntax into epydoc syntax
+ comment=comment.replace('\\param', '@param').replace('\\return', '@return')
+
+ if debug:
+ print '********************'
+ print l
+ print '-------->'
+ print "%s (%s)" % (method, rtype)
+ for typ, name in params:
+ print " %s (%s)" % (name, typ)
+ print '********************'
+ yield (rtype,
+ method,
+ params,
+ comment)
+ comment=''
+
+ def dump_methods(self):
+ print "** Defined functions **"
+ for (rtype, name, params, comment) in self.methods:
+ print "%(name)s (%(rtype)s):" % locals()
+ for t, n in params:
+ print " %(n)s (%(t)s)" % locals()
+
+ def dump_enums(self):
+ print "** Defined enums **"
+ for (typ, name, values, comment) in self.enums:
+ print "%(name)s (%(typ)s):" % locals()
+ for k, v in values:
+ print " %(k)s=%(v)s" % locals()
+
+class PythonGenerator(object):
+ # C-type to ctypes/python type conversion.
+ # Note that enum types conversions are generated (cf convert_enum_names)
+ type2class={
+ 'libvlc_exception_t*': 'ctypes.POINTER(VLCException)',
+
+ 'libvlc_media_player_t*': 'MediaPlayer',
+ 'libvlc_instance_t*': 'Instance',
+ 'libvlc_media_t*': 'Media',
+ 'libvlc_log_t*': 'Log',
+ 'libvlc_log_iterator_t*': 'LogIterator',
+ 'libvlc_log_message_t*': 'LogMessage',
+ 'libvlc_event_type_t': 'ctypes.c_uint',
+ 'libvlc_event_manager_t*': 'EventManager',
+ 'libvlc_media_discoverer_t*': 'MediaDiscoverer',
+ 'libvlc_media_library_t*': 'MediaLibrary',
+ 'libvlc_media_list_t*': 'MediaList',
+ 'libvlc_media_list_player_t*': 'MediaListPlayer',
+ 'libvlc_media_list_view_t*': 'MediaListView',
+ 'libvlc_track_description_t*': 'TrackDescription',
+ 'libvlc_audio_output_t*': 'AudioOutput',
+
+ 'mediacontrol_Instance*': 'MediaControl',
+ 'mediacontrol_Exception*': 'MediaControlException',
+ 'mediacontrol_RGBPicture*': 'ctypes.POINTER(RGBPicture)',
+ 'mediacontrol_PlaylistSeq*': 'MediaControlPlaylistSeq',
+ 'mediacontrol_Position*': 'ctypes.POINTER(MediaControlPosition)',
+ 'mediacontrol_StreamInformation*': 'ctypes.POINTER(MediaControlStreamInformation)',
+ 'WINDOWHANDLE': 'ctypes.c_ulong',
+
+ 'void': 'None',
+ 'void*': 'ctypes.c_void_p',
+ 'short': 'ctypes.c_short',
+ 'char*': 'ctypes.c_char_p',
+ 'char**': 'ListPOINTER(ctypes.c_char_p)',
+ 'uint32_t': 'ctypes.c_uint',
+ 'float': 'ctypes.c_float',
+ 'unsigned': 'ctypes.c_uint',
+ 'int': 'ctypes.c_int',
+ '...': 'FIXMEva_list',
+ 'libvlc_callback_t': 'ctypes.c_void_p',
+ 'libvlc_time_t': 'ctypes.c_longlong',
+ }
+
+ # Defined python classes, i.e. classes for which we want to generate
+ # class wrappers around libvlc functions
+ defined_classes=(
+ 'MediaPlayer',
+ 'Instance',
+ 'Media',
+ 'Log',
+ 'LogIterator',
+ 'EventManager',
+ 'MediaDiscoverer',
+ 'MediaLibrary',
+ 'MediaList',
+ 'MediaListPlayer',
+ 'MediaListView',
+ 'TrackDescription',
+ 'AudioOutput',
+ 'MediaControl',
+ )
+
+ def __init__(self, parser=None):
+ self.parser=parser
+
+ # Generate python names for enums
+ self.type2class.update(self.convert_enum_names(parser.enums))
+ self.check_types()
+
+ # Definition of prefixes that we can strip from method names when
+ # wrapping them into class methods
+ self.prefixes=dict( (v, k[:-2])
+ for (k, v) in self.type2class.iteritems()
+ if v in self.defined_classes )
+ self.prefixes['MediaControl']='mediacontrol_'
+
+ def save(self, filename=None):
+ if filename is None or filename == '-':
+ self.fd=sys.stdout
+ else:
+ self.fd=open(filename, 'w')
+
+ self.insert_code('header.py')
+ self.generate_enums(self.parser.enums)
+ wrapped_methods=self.generate_wrappers(self.parser.methods)
+ for l in self.parser.methods:
+ self.output_ctypes(*l)
+ self.insert_code('footer.py')
+
+ all_methods=set( t[1] for t in self.parser.methods )
+ not_wrapped=all_methods.difference(wrapped_methods)
+ self.output("# Not wrapped methods:")
+ for m in not_wrapped:
+ self.output("# ", m)
+
+ if self.fd != sys.stdout:
+ self.fd.close()
+
+ def output(self, *p):
+ self.fd.write(" ".join(p))
+ self.fd.write("\n")
+
+ def check_types(self):
+ """Make sure that all types are properly translated.
+
+ This method must be called *after* convert_enum_names, since
+ the latter populates type2class with converted enum names.
+ """
+ for (rt, met, params, c) in self.parser.methods: