[vlc-devel] commit: python-ctypes: generate classes for enum typedefs (Olivier Aubert )
git version control
git at videolan.org
Fri Jul 31 14:16:04 CEST 2009
vlc | branch: master | Olivier Aubert <olivier.aubert at liris.cnrs.fr> | Fri Jul 31 14:15:43 2009 +0200| [d7b1ce91d6a9cbfecfef9fca762d6db3abf80475] | committer: Olivier Aubert
python-ctypes: generate classes for enum typedefs
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d7b1ce91d6a9cbfecfef9fca762d6db3abf80475
---
bindings/python-ctypes/TODO | 4 -
bindings/python-ctypes/generate.py | 118 ++++++++++++++++++++++++++++++++---
bindings/python-ctypes/header.py | 16 -----
3 files changed, 107 insertions(+), 31 deletions(-)
diff --git a/bindings/python-ctypes/TODO b/bindings/python-ctypes/TODO
index 79398f1..eab5b13 100644
--- a/bindings/python-ctypes/TODO
+++ b/bindings/python-ctypes/TODO
@@ -1,9 +1,5 @@
* Investigate memory management
-* Find how to properly define enums
-
-* Autogenerate enums from include files
-
* Implement event callbacks
* Write a test suite
diff --git a/bindings/python-ctypes/generate.py b/bindings/python-ctypes/generate.py
index 41f69b3..473980c 100755
--- a/bindings/python-ctypes/generate.py
+++ b/bindings/python-ctypes/generate.py
@@ -87,13 +87,15 @@ paramlist_re=re.compile('\s*,\s*')
comment_re=re.compile('\\param\s+(\S+)')
python_param_re=re.compile('(@param\s+\S+)(.+)')
forward_re=re.compile('.+\(\s*(.+?)\s*\)(\s*\S+)')
+enum_re=re.compile('typedef\s+(enum)\s*(\S+\s*)?\{\s*(.+)\s*\}\s*(\S+);')
# Definition of parameter passing mode for types. This should not be
# hardcoded this way, but works alright ATM.
parameter_passing=DefaultDict(default=1)
parameter_passing['libvlc_exception_t*']=3
-# C-type to ctypes/python type conversion
+# C-type to ctypes/python type conversion.
+# Note that enum types conversions are generated (cf convert_enum_names)
typ2class={
'libvlc_exception_t*': 'ctypes.POINTER(VLCException)',
@@ -119,28 +121,20 @@ typ2class={
'mediacontrol_PlaylistSeq*': 'MediaControlPlaylistSeq',
'mediacontrol_Position*': 'MediaControlPosition',
'mediacontrol_StreamInformation*': 'MediaControlStreamInformation',
- 'mediacontrol_PositionOrigin': 'ctypes.c_uint',
- 'mediacontrol_PositionKey': 'ctypes.c_uint',
'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',
- 'void': 'None',
- 'void*': 'ctypes.c_void_p',
'int': 'ctypes.c_int',
'...': 'FIXMEva_list',
'libvlc_callback_t': 'FIXMEcallback',
'libvlc_time_t': 'ctypes.c_longlong',
- 'libvlc_video_marquee_int_option_t': 'ctypes.c_int',
- 'libvlc_video_marquee_string_option_t': 'ctypes.c_char_p',
- # FIXME: enums -> to be processed
- 'libvlc_media_option_t': 'ctypes.c_uint',
- 'libvlc_meta_t': 'ctypes.c_uint',
- 'libvlc_state_t': 'State',
}
# Defined python classes, i.e. classes for which we want to generate
@@ -211,6 +205,101 @@ def generate_header(classes=None):
print l,
f.close()
+def convert_enum_names(enums):
+ res={}
+ for (typ, name, values) in enums:
+ if typ != 'enum':
+ raise Exception('This method only handles enums')
+ pyname=re.findall('(libvlc|mediacontrol)_(.+?)(_t)?$', name)[0][1]
+ if '_' in pyname:
+ pyname=pyname.title().replace('_', '')
+ else:
+ pyname=pyname.capitalize()
+ res[name]=pyname
+ return res
+
+def generate_enums(enums):
+ for (typ, name, values) in enums:
+ if typ != 'enum':
+ raise Exception('This method only handles enums')
+ pyname=typ2class[name]
+
+ print "class %s(ctypes.c_uint):" % pyname
+
+ conv={}
+ # Convert symbol names
+ for k, v in values:
+ n=k.split('_')[-1]
+ if len(n) == 1:
+ # Single character. Some symbols use 1_1, 5_1, etc.
+ n="_".join( k.split('_')[:-2] )
+ if re.match('^[0-9]', n):
+ # Cannot start an identifier with a number
+ n='_'+n
+ conv[k]=n
+
+ for k, v in values:
+ print " %s=%s" % (conv[k], v)
+
+ print " _names={"
+ for k, v in values:
+ print " %s: '%s'," % (v, conv[k])
+ print " }"
+
+ print """
+ def __repr__(self):
+ return ".".join((self.__class__.__module__, self.__class__.__name__, self._names[self.value]))
+"""
+
+def parse_typedef(name):
+ """Parse include file for typedef expressions.
+
+ This generates a tuple for each typedef:
+ (type, name, value_list)
+ with type == 'enum' (for the moment) and value_list being a list of (name, value)
+ Note that values are string, since this is intended for code generation.
+ """
+ f=open(name, 'r')
+ accumulator=''
+ for l in f:
+ # Note: lstrip() should not be necessary, but there is 1 badly
+ # formatted comment in vlc1.0.0 includes
+ if l.lstrip().startswith('/**'):
+ comment=''
+ continue
+ elif l.startswith(' * '):
+ comment = comment + l[3:]
+ continue
+
+ l=l.strip()
+
+ if accumulator:
+ accumulator=" ".join( (accumulator, l) )
+ if l.endswith(';'):
+ # End of definition
+ l=accumulator
+ accumulator=''
+ elif l.startswith('typedef enum') and not l.endswith(';'):
+ # Multiline definition. Accumulate until end of definition
+ accumulator=l
+ continue
+
+ m=enum_re.match(l)
+ if m:
+ values=[]
+ (typ, dummy, data, name)=m.groups()
+ for i, l in enumerate(paramlist_re.split(data)):
+ l=l.strip()
+ if l.startswith('/*'):
+ continue
+ if '=' in l:
+ # A value was specified. Use it.
+ values.append(re.split('\s*=\s*', l))
+ else:
+ if l:
+ values.append( (l, str(i)) )
+ yield (typ, name, values)
+
def parse_include(name):
"""Parse include file.
@@ -429,6 +518,12 @@ class %(name)s(object):
return ret
if __name__ == '__main__':
+ enums=[]
+ for name in sys.argv[1:]:
+ enums.extend(list(parse_typedef(name)))
+ # Generate python names for enums
+ typ2class.update(convert_enum_names(enums))
+
methods=[]
for name in sys.argv[1:]:
methods.extend(list(parse_include(name)))
@@ -436,6 +531,7 @@ if __name__ == '__main__':
sys.exit(0)
generate_header()
+ generate_enums(enums)
wrapped=generate_wrappers(methods)
for l in methods:
output_ctypes(*l)
diff --git a/bindings/python-ctypes/header.py b/bindings/python-ctypes/header.py
index ae2e8e0..6684d12 100755
--- a/bindings/python-ctypes/header.py
+++ b/bindings/python-ctypes/header.py
@@ -101,22 +101,6 @@ class MediaControlPositionOrigin(ctypes.c_uint):
def __repr__(self):
return self.enum[self.value]
-class State(ctypes.c_uint):
- # FIXME: should be improved (State.NothingSpecial should hold the value)
- # and maybe auto-generated from typedefs
- enum=(
- 'NothingSpecial',
- 'Opening',
- 'Buffering',
- 'Playing',
- 'Paused',
- 'Stopped',
- 'Ended',
- 'Error',
- )
- def __repr__(self):
- return self.enum[self.value]
-
class MediaControlException(ctypes.Structure):
_fields_= [
('code', ctypes.c_int),
More information about the vlc-devel
mailing list