enums.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. ##
  2. ## This file is part of the libsigrok project.
  3. ##
  4. ## Copyright (C) 2014 Martin Ling <martin-sigrok@earth.li>
  5. ##
  6. ## This program is free software: you can redistribute it and/or modify
  7. ## it under the terms of the GNU General Public License as published by
  8. ## the Free Software Foundation, either version 3 of the License, or
  9. ## (at your option) any later version.
  10. ##
  11. ## This program is distributed in the hope that it will be useful,
  12. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ## GNU General Public License for more details.
  15. ##
  16. ## You should have received a copy of the GNU General Public License
  17. ## along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. ##
  19. from __future__ import print_function
  20. from xml.etree import ElementTree
  21. from collections import OrderedDict
  22. import sys, os, re
  23. index_file = sys.argv[1]
  24. # Get directory this script is in.
  25. dirname = os.path.dirname(os.path.realpath(__file__))
  26. outdirname = "bindings"
  27. if not os.path.exists(os.path.join(outdirname, 'cxx/include/libsigrokcxx')):
  28. os.makedirs(os.path.join(outdirname, 'cxx/include/libsigrokcxx'))
  29. if not os.path.exists(os.path.join(outdirname, 'swig')):
  30. os.makedirs(os.path.join(outdirname, 'swig'))
  31. mapping = dict([
  32. ('sr_loglevel', ('LogLevel', 'Log verbosity level')),
  33. ('sr_packettype', ('PacketType', 'Type of datafeed packet')),
  34. ('sr_mq', ('Quantity', 'Measured quantity')),
  35. ('sr_unit', ('Unit', 'Unit of measurement')),
  36. ('sr_mqflag', ('QuantityFlag', 'Flag applied to measured quantity')),
  37. ('sr_configkey', ('ConfigKey', 'Configuration key')),
  38. ('sr_configcap', ('Capability', 'Configuration capability')),
  39. ('sr_datatype', ('DataType', 'Configuration data type')),
  40. ('sr_channeltype', ('ChannelType', 'Channel type')),
  41. ('sr_trigger_matches', ('TriggerMatchType', 'Trigger match type')),
  42. ('sr_output_flag', ('OutputFlag', 'Flag applied to output modules'))])
  43. index = ElementTree.parse(index_file)
  44. # Build mapping between class names and enumerations.
  45. classes = OrderedDict()
  46. for compound in index.findall('compound'):
  47. if compound.attrib['kind'] != 'file':
  48. continue
  49. filename = os.path.join(
  50. os.path.dirname(index_file),
  51. '%s.xml' % compound.attrib['refid'])
  52. doc = ElementTree.parse(filename)
  53. for section in doc.find('compounddef').findall('sectiondef'):
  54. if section.attrib["kind"] != 'enum':
  55. continue
  56. for member in section.findall('memberdef'):
  57. if member.attrib["kind"] != 'enum':
  58. continue
  59. name = member.find('name').text
  60. if name in mapping:
  61. classes[member] = mapping[name]
  62. header = open(os.path.join(outdirname, 'cxx/include/libsigrokcxx/enums.hpp'), 'w')
  63. code = open(os.path.join(outdirname, 'cxx/enums.cpp'), 'w')
  64. swig = open(os.path.join(outdirname, 'swig/enums.i'), 'w')
  65. for file in (header, code):
  66. print("/* Generated file - edit enums.py instead! */", file=file)
  67. print("namespace sigrok {", file=header)
  68. # Template for beginning of class declaration and public members.
  69. header_public_template = """
  70. template<> const SR_API std::map<const enum {enumname}, const {classname} * const> EnumValue<{classname}, enum {enumname}>::_values;
  71. /** {brief} */
  72. class SR_API {classname} : public EnumValue<{classname}, enum {enumname}>
  73. {{
  74. public:
  75. """
  76. # Template for beginning of private members.
  77. header_private_template = """
  78. protected:
  79. {classname}(enum {enumname} id, const char name[]) : EnumValue(id, name) {{}}
  80. """
  81. def get_text(node):
  82. return str.join('\n\n',
  83. [p.text.rstrip() for p in node.findall('para')])
  84. for enum, (classname, classbrief) in classes.items():
  85. enum_name = enum.find('name').text
  86. members = enum.findall('enumvalue')
  87. member_names = [m.find('name').text for m in members]
  88. trimmed_names = [re.sub("^SR_[A-Z]+_", "", n) for n in member_names]
  89. briefs = [get_text(m.find('briefdescription')) for m in members]
  90. # Begin class and public declarations
  91. print(header_public_template.format(
  92. brief=classbrief, classname=classname, enumname=enum_name), file=header)
  93. # Declare public pointers for each enum value
  94. for trimmed_name, brief in zip(trimmed_names, briefs):
  95. if brief:
  96. print('\t/** %s */' % brief, file=header)
  97. print('\tstatic const %s * const %s;' % (
  98. classname, trimmed_name), file=header)
  99. # Declare additional methods if present
  100. filename = os.path.join(dirname, "%s_methods.hpp" % classname)
  101. if os.path.exists(filename):
  102. print(str.join('', open(filename).readlines()), file=header)
  103. # Begin private declarations
  104. print(header_private_template.format(
  105. classname=classname, enumname=enum_name), file=header)
  106. # Declare private constants for each enum value
  107. for trimmed_name in trimmed_names:
  108. print('\tstatic const %s _%s;' % (classname, trimmed_name), file=header)
  109. # End class declaration
  110. print('};', file=header)
  111. # Define private constants for each enum value
  112. for name, trimmed_name in zip(member_names, trimmed_names):
  113. print('const %s %s::_%s = %s(%s, "%s");' % (
  114. classname, classname, trimmed_name, classname, name, trimmed_name),
  115. file=code)
  116. # Define public pointers for each enum value
  117. for trimmed_name in trimmed_names:
  118. print('const %s * const %s::%s = &%s::_%s;' % (
  119. classname, classname, trimmed_name, classname, trimmed_name),
  120. file=code)
  121. # Define map of enum values to constants
  122. print('template<> const SR_API std::map<const enum %s, const %s * const> EnumValue<%s, enum %s>::_values = {' % (
  123. enum_name, classname, classname, enum_name), file=code)
  124. for name, trimmed_name in zip(member_names, trimmed_names):
  125. print('\t{%s, %s::%s},' % (name, classname, trimmed_name), file=code)
  126. print('};', file=code)
  127. # Define additional methods if present
  128. filename = os.path.join(dirname, "%s_methods.cpp" % classname)
  129. if os.path.exists(filename):
  130. print(str.join('', open(filename).readlines()), file=code)
  131. # Map EnumValue::id() and EnumValue::name() as SWIG attributes.
  132. print('%%attribute(sigrok::%s, int, id, id);' % classname, file=swig)
  133. print('%%attributestring(sigrok::%s, std::string, name, name);' % classname,
  134. file=swig)
  135. # Instantiate EnumValue template for SWIG
  136. print('%%template(EnumValue%s) sigrok::EnumValue<sigrok::%s, enum %s>;' % (
  137. classname, classname, enum_name), file=swig)
  138. # Apply any language-specific extras.
  139. print('%%enumextras(%s);' % classname, file=swig)
  140. # Declare additional attributes if present
  141. filename = os.path.join(dirname, "%s_methods.i" % classname)
  142. if os.path.exists(filename):
  143. print(str.join('', open(filename).readlines()), file=swig)
  144. print("}", file=header)