17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#!/usr/bin/python 27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 37ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' 47ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohennanopb_version = "nanopb-0.2.8-dev" 57ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 67ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport sys 77ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 87ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohentry: 97ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Add some dummy imports to keep packaging tools happy. 107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import google, distutils.util # bbfreeze seems to need these 117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import pkg_resources # pyinstaller / protobuf 2.5 seem to need these 127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenexcept: 137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Don't care, we will error out later if it is actually important. 147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pass 157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohentry: 177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import google.protobuf.text_format as text_format 187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import google.protobuf.descriptor_pb2 as descriptor 197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenexcept: 207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write(''' 217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ************************************************************* 227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *** Could not import the Google protobuf Python libraries *** 237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *** Try installing package 'python-protobuf' or similar. *** 247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ************************************************************* 257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' + '\n') 267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise 277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohentry: 297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import proto.nanopb_pb2 as nanopb_pb2 307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import proto.plugin_pb2 as plugin_pb2 317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenexcept: 327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write(''' 337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ******************************************************************** 347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *** Failed to import the protocol definitions for generator. *** 357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *** You have to run 'make' in the nanopb/generator/proto folder. *** 367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ******************************************************************** 377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' + '\n') 387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise 397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Generation of single fields 427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport time 457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport os.path 467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Values are tuple (c type, pb type, encoded size) 487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenFieldD = descriptor.FieldDescriptorProto 497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendatatypes = { 507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_BOOL: ('bool', 'BOOL', 1), 517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_DOUBLE: ('double', 'DOUBLE', 8), 527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_FIXED32: ('uint32_t', 'FIXED32', 4), 537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_FIXED64: ('uint64_t', 'FIXED64', 8), 547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_FLOAT: ('float', 'FLOAT', 4), 557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_INT32: ('int32_t', 'INT32', 10), 567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_INT64: ('int64_t', 'INT64', 10), 577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_SFIXED32: ('int32_t', 'SFIXED32', 4), 587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_SFIXED64: ('int64_t', 'SFIXED64', 8), 597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_SINT32: ('int32_t', 'SINT32', 5), 607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_SINT64: ('int64_t', 'SINT64', 10), 617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_UINT32: ('uint32_t', 'UINT32', 5), 627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FieldD.TYPE_UINT64: ('uint64_t', 'UINT64', 10) 637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass Names: 667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Keeps a set of nested names and formats them to C identifier.''' 677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __init__(self, parts = ()): 687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if isinstance(parts, Names): 697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen parts = parts.parts 707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.parts = tuple(parts) 717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __str__(self): 737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '_'.join(self.parts) 747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __add__(self, other): 767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if isinstance(other, (str, unicode)): 777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return Names(self.parts + (other,)) 787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif isinstance(other, tuple): 797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return Names(self.parts + other) 807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise ValueError("Name parts should be of type str") 827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __eq__(self, other): 847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return isinstance(other, Names) and self.parts == other.parts 857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef names_from_type_name(type_name): 877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Parse Names() from FieldDescriptorProto type_name''' 887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if type_name[0] != '.': 897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise NotImplementedError("Lookup of non-absolute type names is not supported") 907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return Names(type_name[1:].split('.')) 917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef varint_max_size(max_value): 937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Returns the maximum number of bytes a varint can take when encoded.''' 947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for i in range(1, 11): 957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (max_value >> (i * 7)) == 0: 967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return i 977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise ValueError("Value too large for varint: " + str(max_value)) 987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenassert varint_max_size(0) == 1 1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenassert varint_max_size(127) == 1 1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenassert varint_max_size(128) == 2 1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass EncodedSize: 1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Class used to represent the encoded size of a field or a message. 1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Consists of a combination of symbolic sizes and integer sizes.''' 1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __init__(self, value = 0, symbols = []): 1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if isinstance(value, (str, Names)): 1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen symbols = [str(value)] 1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen value = 0 1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.value = value 1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.symbols = symbols 1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __add__(self, other): 1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if isinstance(other, (int, long)): 1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return EncodedSize(self.value + other, self.symbols) 1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif isinstance(other, (str, Names)): 1177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return EncodedSize(self.value, self.symbols + [str(other)]) 1187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif isinstance(other, EncodedSize): 1197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return EncodedSize(self.value + other.value, self.symbols + other.symbols) 1207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 1217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise ValueError("Cannot add size: " + repr(other)) 1227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __mul__(self, other): 1247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if isinstance(other, (int, long)): 1257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return EncodedSize(self.value * other, [str(other) + '*' + s for s in self.symbols]) 1267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 1277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise ValueError("Cannot multiply size: " + repr(other)) 1287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __str__(self): 1307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not self.symbols: 1317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return str(self.value) 1327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 1337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '(' + str(self.value) + ' + ' + ' + '.join(self.symbols) + ')' 1347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def upperlimit(self): 1367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not self.symbols: 1377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return self.value 1387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 1397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 2**32 - 1 1407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass Enum: 1427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __init__(self, names, desc, enum_options): 1437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''desc is EnumDescriptorProto''' 1447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.options = enum_options 1467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.names = names + desc.name 1477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if enum_options.long_names: 1497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.values = [(self.names + x.name, x.number) for x in desc.value] 1507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 1517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.values = [(names + x.name, x.number) for x in desc.value] 1527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.value_longnames = [self.names + x.name for x in desc.value] 1547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __str__(self): 1567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = 'typedef enum _%s {\n' % self.names 1577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ',\n'.join([" %s = %d" % x for x in self.values]) 1587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '\n} %s;' % self.names 1597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 1607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass Field: 1627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __init__(self, struct_name, desc, field_options): 1637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''desc is FieldDescriptorProto''' 1647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.tag = desc.number 1657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.struct_name = struct_name 1667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.name = desc.name 1677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.default = None 1687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.max_size = None 1697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.max_count = None 1707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.array_decl = "" 1717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.enc_size = None 1727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = None 1737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Parse field options 1757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.HasField("max_size"): 1767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.max_size = field_options.max_size 1777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.HasField("max_count"): 1797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.max_count = field_options.max_count 1807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if desc.HasField('default_value'): 1827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.default = desc.default_value 1837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Check field rules, i.e. required/optional/repeated. 1857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen can_be_static = True 1867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if desc.label == FieldD.LABEL_REQUIRED: 1877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.rules = 'REQUIRED' 1887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif desc.label == FieldD.LABEL_OPTIONAL: 1897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.rules = 'OPTIONAL' 1907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif desc.label == FieldD.LABEL_REPEATED: 1917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.rules = 'REPEATED' 1927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.max_count is None: 1937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen can_be_static = False 1947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 1957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.array_decl = '[%d]' % self.max_count 1967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 1977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise NotImplementedError(desc.label) 1987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Check if the field can be implemented with static allocation 2007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # i.e. whether the data size is known. 2017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if desc.type == FieldD.TYPE_STRING and self.max_size is None: 2027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen can_be_static = False 2037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if desc.type == FieldD.TYPE_BYTES and self.max_size is None: 2057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen can_be_static = False 2067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Decide how the field data will be allocated 2087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.type == nanopb_pb2.FT_DEFAULT: 2097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if can_be_static: 2107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen field_options.type = nanopb_pb2.FT_STATIC 2117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 2127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen field_options.type = nanopb_pb2.FT_CALLBACK 2137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.type == nanopb_pb2.FT_STATIC and not can_be_static: 2157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise Exception("Field %s is defined as static, but max_size or " 2167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen "max_count is not given." % self.name) 2177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.type == nanopb_pb2.FT_STATIC: 2197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.allocation = 'STATIC' 2207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif field_options.type == nanopb_pb2.FT_POINTER: 2217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.allocation = 'POINTER' 2227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif field_options.type == nanopb_pb2.FT_CALLBACK: 2237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.allocation = 'CALLBACK' 2247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 2257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise NotImplementedError(field_options.type) 2267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Decide the C data type to use in the struct. 2287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if datatypes.has_key(desc.type): 2297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype, self.pbtype, self.enc_size = datatypes[desc.type] 2307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif desc.type == FieldD.TYPE_ENUM: 2317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.pbtype = 'ENUM' 2327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = names_from_type_name(desc.type_name) 2337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.default is not None: 2347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.default = self.ctype + self.default 2357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.enc_size = 5 # protoc rejects enum values > 32 bits 2367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif desc.type == FieldD.TYPE_STRING: 2377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.pbtype = 'STRING' 2387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = 'char' 2397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.allocation == 'STATIC': 2407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = 'char' 2417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.array_decl += '[%d]' % self.max_size 2427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.enc_size = varint_max_size(self.max_size) + self.max_size 2437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif desc.type == FieldD.TYPE_BYTES: 2447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.pbtype = 'BYTES' 2457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.allocation == 'STATIC': 2467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = self.struct_name + self.name + 't' 2477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.enc_size = varint_max_size(self.max_size) + self.max_size 2487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.allocation == 'POINTER': 2497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = 'pb_bytes_array_t' 2507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif desc.type == FieldD.TYPE_MESSAGE: 2517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.pbtype = 'MESSAGE' 2527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = self.submsgname = names_from_type_name(desc.type_name) 2537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.enc_size = None # Needs to be filled in after the message type is available 2547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 2557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise NotImplementedError(desc.type) 2567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __cmp__(self, other): 2587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return cmp(self.tag, other.tag) 2597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __str__(self): 2617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = '' 2627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.allocation == 'POINTER': 2637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.rules == 'REPEATED': 2647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' size_t ' + self.name + '_count;\n' 2657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.pbtype == 'MESSAGE': 2677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Use struct definition, so recursive submessages are possible 2687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' struct _%s *%s;' % (self.ctype, self.name) 2697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.rules == 'REPEATED' and self.pbtype in ['STRING', 'BYTES']: 2707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # String/bytes arrays need to be defined as pointers to pointers 2717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' %s **%s;' % (self.ctype, self.name) 2727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 2737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' %s *%s;' % (self.ctype, self.name) 2747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.allocation == 'CALLBACK': 2757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' pb_callback_t %s;' % self.name 2767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 2777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.rules == 'OPTIONAL' and self.allocation == 'STATIC': 2787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' bool has_' + self.name + ';\n' 2797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.rules == 'REPEATED' and self.allocation == 'STATIC': 2807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' size_t ' + self.name + '_count;\n' 2817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' %s %s%s;' % (self.ctype, self.name, self.array_decl) 2827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 2837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def types(self): 2857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Return definitions for any special types this field might need.''' 2867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.pbtype == 'BYTES' and self.allocation == 'STATIC': 2877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = 'typedef struct {\n' 2887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' size_t size;\n' 2897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' uint8_t bytes[%d];\n' % self.max_size 2907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '} %s;\n' % self.ctype 2917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 2927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = None 2937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 2947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 2957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def default_decl(self, declaration_only = False): 2967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Return definition for this field's default value.''' 2977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.default is None: 2987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return None 2997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ctype, default = self.ctype, self.default 3017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen array_decl = '' 3027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.pbtype == 'STRING': 3047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.allocation != 'STATIC': 3057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return None # Not implemented 3067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen array_decl = '[%d]' % self.max_size 3087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default = str(self.default).encode('string_escape') 3097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default = default.replace('"', '\\"') 3107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default = '"' + default + '"' 3117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.pbtype == 'BYTES': 3127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.allocation != 'STATIC': 3137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return None # Not implemented 3147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen data = self.default.decode('string_escape') 3167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen data = ['0x%02x' % ord(c) for c in data] 3177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default = '{%d, {%s}}' % (len(data), ','.join(data)) 3187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.pbtype in ['FIXED32', 'UINT32']: 3197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default += 'u' 3207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.pbtype in ['FIXED64', 'UINT64']: 3217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default += 'ull' 3227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.pbtype in ['SFIXED64', 'INT64']: 3237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default += 'll' 3247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if declaration_only: 3267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 'extern const %s %s_default%s;' % (ctype, self.struct_name + self.name, array_decl) 3277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 3287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 'const %s %s_default%s = %s;' % (ctype, self.struct_name + self.name, array_decl, default) 3297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def tags(self): 3317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Return the #define for the tag number of this field.''' 3327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen identifier = '%s_%s_tag' % (self.struct_name, self.name) 3337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '#define %-40s %d\n' % (identifier, self.tag) 3347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def pb_field_t(self, prev_field_name): 3367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Return the pb_field_t initializer to use in the constant array. 3377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen prev_field_name is the name of the previous field or None. 3387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 3397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = ' PB_FIELD2(%3d, ' % self.tag 3407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '%-8s, ' % self.pbtype 3417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '%s, ' % self.rules 3427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '%-8s, ' % self.allocation 3437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '%s, ' % ("FIRST" if not prev_field_name else "OTHER") 3447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '%s, ' % self.struct_name 3457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '%s, ' % self.name 3467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '%s, ' % (prev_field_name or self.name) 3477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.pbtype == 'MESSAGE': 3497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '&%s_fields)' % self.submsgname 3507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.default is None: 3517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '0)' 3527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.pbtype in ['BYTES', 'STRING'] and self.allocation != 'STATIC': 3537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '0)' # Arbitrary size default values not implemented 3547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.rules == 'OPTEXT': 3557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '0)' # Default value for extensions is not implemented 3567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 3577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '&%s_default)' % (self.struct_name + self.name) 3587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 3607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def largest_field_value(self): 3627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Determine if this field needs 16bit or 32bit pb_field_t structure to compile properly. 3637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Returns numeric value or a C-expression for assert.''' 3647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.pbtype == 'MESSAGE': 3657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.rules == 'REPEATED' and self.allocation == 'STATIC': 3667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 'pb_membersize(%s, %s[0])' % (self.struct_name, self.name) 3677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 3687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 'pb_membersize(%s, %s)' % (self.struct_name, self.name) 3697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return max(self.tag, self.max_size, self.max_count) 3717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def encoded_size(self, allmsgs): 3737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Return the maximum size that this field can take when encoded, 3747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen including the field tag. If the size cannot be determined, returns 3757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen None.''' 3767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.allocation != 'STATIC': 3787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return None 3797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.pbtype == 'MESSAGE': 3817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in allmsgs: 3827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if msg.name == self.submsgname: 3837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen encsize = msg.encoded_size(allmsgs) 3847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if encsize is None: 3857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return None # Submessage size is indeterminate 3867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Include submessage length prefix 3887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen encsize += varint_max_size(encsize.upperlimit()) 3897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen break 3907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 3917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Submessage cannot be found, this currently occurs when 3927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # the submessage type is defined in a different file. 3937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Instead of direct numeric value, reference the size that 3947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # has been #defined in the other file. 3957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen encsize = EncodedSize(self.submsgname + 'size') 3967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 3977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # We will have to make a conservative assumption on the length 3987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # prefix size, though. 3997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen encsize += 5 4007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif self.enc_size is None: 4027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise RuntimeError("Could not determine encoded size for %s.%s" 4037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen % (self.struct_name, self.name)) 4047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 4057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen encsize = EncodedSize(self.enc_size) 4067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen encsize += varint_max_size(self.tag << 3) # Tag + wire type 4087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.rules == 'REPEATED': 4107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Decoders must be always able to handle unpacked arrays. 4117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Therefore we have to reserve space for it, even though 4127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # we emit packed arrays ourselves. 4137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen encsize *= self.max_count 4147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return encsize 4167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass ExtensionRange(Field): 4197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __init__(self, struct_name, range_start, field_options): 4207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Implements a special pb_extension_t* field in an extensible message 4217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen structure. The range_start signifies the index at which the extensions 4227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen start. Not necessarily all tags above this are extensions, it is merely 4237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen a speed optimization. 4247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 4257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.tag = range_start 4267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.struct_name = struct_name 4277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.name = 'extensions' 4287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.pbtype = 'EXTENSION' 4297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.rules = 'OPTIONAL' 4307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.allocation = 'CALLBACK' 4317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ctype = 'pb_extension_t' 4327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.array_decl = '' 4337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.default = None 4347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.max_size = 0 4357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.max_count = 0 4367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __str__(self): 4387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return ' pb_extension_t *extensions;' 4397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def types(self): 4417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return None 4427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def tags(self): 4447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '' 4457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def encoded_size(self, allmsgs): 4477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # We exclude extensions from the count, because they cannot be known 4487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # until runtime. Other option would be to return None here, but this 4497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # way the value remains useful if extensions are not used. 4507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return EncodedSize(0) 4517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass ExtensionField(Field): 4537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __init__(self, struct_name, desc, field_options): 4547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.fullname = struct_name + desc.name 4557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.extendee_name = names_from_type_name(desc.extendee) 4567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Field.__init__(self, self.fullname + 'struct', desc, field_options) 4577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.rules != 'OPTIONAL': 4597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.skip = True 4607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 4617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.skip = False 4627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.rules = 'OPTEXT' 4637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def tags(self): 4657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Return the #define for the tag number of this field.''' 4667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen identifier = '%s_tag' % self.fullname 4677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '#define %-40s %d\n' % (identifier, self.tag) 4687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def extension_decl(self): 4707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Declaration of the extension type in the .pb.h file''' 4717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.skip: 4727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen msg = '/* Extension field %s was skipped because only "optional"\n' % self.fullname 4737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen msg +=' type of extension fields is currently supported. */\n' 4747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return msg 4757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 'extern const pb_extension_type_t %s;\n' % self.fullname 4777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def extension_def(self): 4797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Definition of the extension type in the .pb.c file''' 4807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.skip: 4827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '' 4837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = 'typedef struct {\n' 4857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += str(self) 4867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '\n} %s;\n\n' % self.struct_name 4877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ('static const pb_field_t %s_field = \n %s;\n\n' % 4887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen (self.fullname, self.pb_field_t(None))) 4897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += 'const pb_extension_type_t %s = {\n' % self.fullname 4907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' NULL,\n' 4917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' NULL,\n' 4927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' &%s_field\n' % self.fullname 4937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '};\n' 4947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 4957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 4977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 4987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Generation of messages (structures) 4997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 5007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass Message: 5037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __init__(self, names, desc, message_options): 5047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.name = names 5057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.fields = [] 5067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for f in desc.field: 5087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen field_options = get_nanopb_suboptions(f, message_options, self.name + f.name) 5097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.type != nanopb_pb2.FT_IGNORE: 5107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.fields.append(Field(self.name, f, field_options)) 5117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if len(desc.extension_range) > 0: 5137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen field_options = get_nanopb_suboptions(desc, message_options, self.name + 'extensions') 5147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen range_start = min([r.start for r in desc.extension_range]) 5157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.type != nanopb_pb2.FT_IGNORE: 5167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.fields.append(ExtensionRange(self.name, range_start, field_options)) 5177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.packed = message_options.packed_struct 5197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ordered_fields = self.fields[:] 5207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen self.ordered_fields.sort() 5217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def get_dependencies(self): 5237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Get list of type names that this structure refers to.''' 5247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return [str(field.ctype) for field in self.fields] 5257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def __str__(self): 5277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = 'typedef struct _%s {\n' % self.name 5287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not self.ordered_fields: 5307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Empty structs are not allowed in C standard. 5317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Therefore add a dummy field if an empty message occurs. 5327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' uint8_t dummy_field;' 5337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '\n'.join([str(f) for f in self.ordered_fields]) 5357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '\n}' 5367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.packed: 5387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' pb_packed' 5397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' %s;' % self.name 5417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if self.packed: 5437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = 'PB_PACKED_STRUCT_START\n' + result 5447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '\nPB_PACKED_STRUCT_END' 5457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 5477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def types(self): 5497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = "" 5507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in self.fields: 5517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen types = field.types() 5527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if types is not None: 5537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += types + '\n' 5547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 5557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def default_decl(self, declaration_only = False): 5577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = "" 5587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in self.fields: 5597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen default = field.default_decl(declaration_only) 5607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if default is not None: 5617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += default + '\n' 5627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 5637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def fields_declaration(self): 5657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = 'extern const pb_field_t %s_fields[%d];' % (self.name, len(self.fields) + 1) 5667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 5677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def fields_definition(self): 5697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = 'const pb_field_t %s_fields[%d] = {\n' % (self.name, len(self.fields) + 1) 5707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen prev = None 5727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in self.ordered_fields: 5737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += field.pb_field_t(prev) 5747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ',\n' 5757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen prev = field.name 5767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += ' PB_LAST_FIELD\n};' 5787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 5797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen def encoded_size(self, allmsgs): 5817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Return the maximum size that this message can take when encoded. 5827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen If the size cannot be determined, returns None. 5837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 5847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size = EncodedSize(0) 5857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in self.fields: 5867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen fsize = field.encoded_size(allmsgs) 5877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if fsize is None: 5887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return None 5897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen size += fsize 5907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return size 5927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 5957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Processing of entire .proto files 5967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 5977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 5997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef iterate_messages(desc, names = Names()): 6007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Recursively find all messages. For each, yield name, DescriptorProto.''' 6017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if hasattr(desc, 'message_type'): 6027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen submsgs = desc.message_type 6037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 6047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen submsgs = desc.nested_type 6057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for submsg in submsgs: 6077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sub_names = names + submsg.name 6087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield sub_names, submsg 6097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for x in iterate_messages(submsg, sub_names): 6117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield x 6127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef iterate_extensions(desc, names = Names()): 6147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Recursively find all extensions. 6157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen For each, yield name, FieldDescriptorProto. 6167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 6177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for extension in desc.extension: 6187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield names, extension 6197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for subname, subdesc in iterate_messages(desc, names): 6217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for extension in subdesc.extension: 6227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield subname, extension 6237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef parse_file(fdesc, file_options): 6257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Takes a FileDescriptorProto and returns tuple (enums, messages, extensions).''' 6267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen enums = [] 6287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen messages = [] 6297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen extensions = [] 6307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if fdesc.package: 6327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen base_name = Names(fdesc.package.split('.')) 6337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 6347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen base_name = Names() 6357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for enum in fdesc.enum_type: 6377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen enum_options = get_nanopb_suboptions(enum, file_options, base_name + enum.name) 6387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen enums.append(Enum(base_name, enum, enum_options)) 6397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for names, message in iterate_messages(fdesc, base_name): 6417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen message_options = get_nanopb_suboptions(message, file_options, names) 6427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen messages.append(Message(names, message, message_options)) 6437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for enum in message.enum_type: 6447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen enum_options = get_nanopb_suboptions(enum, message_options, names + enum.name) 6457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen enums.append(Enum(names, enum, enum_options)) 6467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for names, extension in iterate_extensions(fdesc, base_name): 6487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen field_options = get_nanopb_suboptions(extension, file_options, names) 6497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field_options.type != nanopb_pb2.FT_IGNORE: 6507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen extensions.append(ExtensionField(names, extension, field_options)) 6517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Fix field default values where enum short names are used. 6537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for enum in enums: 6547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not enum.options.long_names: 6557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for message in messages: 6567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in message.fields: 6577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field.default in enum.value_longnames: 6587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen idx = enum.value_longnames.index(field.default) 6597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen field.default = enum.values[idx][0] 6607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return enums, messages, extensions 6627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef toposort2(data): 6647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Topological sort. 6657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen From http://code.activestate.com/recipes/577413-topological-sort/ 6667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen This function is under the MIT license. 6677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 6687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for k, v in data.items(): 6697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen v.discard(k) # Ignore self dependencies 6707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen extra_items_in_deps = reduce(set.union, data.values(), set()) - set(data.keys()) 6717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen data.update(dict([(item, set()) for item in extra_items_in_deps])) 6727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while True: 6737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ordered = set(item for item,dep in data.items() if not dep) 6747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not ordered: 6757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen break 6767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for item in sorted(ordered): 6777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield item 6787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen data = dict([(item, (dep - ordered)) for item,dep in data.items() 6797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if item not in ordered]) 6807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen assert not data, "A cyclic dependency exists amongst %r" % data 6817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef sort_dependencies(messages): 6837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Sort a list of Messages based on dependencies.''' 6847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen dependencies = {} 6857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen message_by_name = {} 6867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for message in messages: 6877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen dependencies[str(message.name)] = set(message.get_dependencies()) 6887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen message_by_name[str(message.name)] = message 6897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msgname in toposort2(dependencies): 6917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if msgname in message_by_name: 6927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield message_by_name[msgname] 6937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 6947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef make_identifier(headername): 6957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Make #ifndef identifier that contains uppercase A-Z and digits 0-9''' 6967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result = "" 6977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for c in headername.upper(): 6987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if c.isalnum(): 6997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += c 7007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 7017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen result += '_' 7027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return result 7037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef generate_header(dependencies, headername, enums, messages, extensions, options): 7057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Generate content for a header file. 7067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Generates strings, which should be concatenated and stored to file. 7077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 7087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Automatically generated nanopb header */\n' 7107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if options.notimestamp: 7117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Generated by %s */\n\n' % (nanopb_version) 7127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 7137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) 7147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen symbol = make_identifier(headername) 7167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#ifndef _PB_%s_\n' % symbol 7177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#define _PB_%s_\n' % symbol 7187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen try: 7197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield options.libformat % ('pb.h') 7207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen except TypeError: 7217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # no %s specified - use whatever was passed in as options.libformat 7227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield options.libformat 7237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for dependency in dependencies: 7267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen noext = os.path.splitext(dependency)[0] 7277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield options.genformat % (noext + '.' + options.extension + '.h') 7287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#ifdef __cplusplus\n' 7317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield 'extern "C" {\n' 7327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#endif\n\n' 7337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Enum definitions */\n' 7357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for enum in enums: 7367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield str(enum) + '\n\n' 7377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Struct definitions */\n' 7397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in sort_dependencies(messages): 7407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield msg.types() 7417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield str(msg) + '\n\n' 7427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if extensions: 7447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Extensions */\n' 7457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for extension in extensions: 7467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield extension.extension_decl() 7477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Default values for struct fields */\n' 7507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in messages: 7517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield msg.default_decl(True) 7527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Field tags (for use in manual encoding/decoding) */\n' 7557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in sort_dependencies(messages): 7567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in msg.fields: 7577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield field.tags() 7587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for extension in extensions: 7597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield extension.tags() 7607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Struct field encoding specification for nanopb */\n' 7637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in messages: 7647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield msg.fields_declaration() + '\n' 7657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Maximum encoded size of messages (where known) */\n' 7687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in messages: 7697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen msize = msg.encoded_size(messages) 7707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if msize is not None: 7717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen identifier = '%s_size' % msg.name 7727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#define %-40s %s\n' % (identifier, msize) 7737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#ifdef __cplusplus\n' 7767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '} /* extern "C" */\n' 7777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#endif\n' 7787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # End of header 7807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n#endif\n' 7817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef generate_source(headername, enums, messages, extensions, options): 7837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Generate content for a source file.''' 7847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Automatically generated nanopb constant definitions */\n' 7867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if options.notimestamp: 7877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Generated by %s */\n\n' % (nanopb_version) 7887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 7897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime()) 7907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield options.genformat % (headername) 7917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 7927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in messages: 7947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield msg.default_decl(False) 7957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n\n' 7977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 7987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in messages: 7997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield msg.fields_definition() + '\n\n' 8007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for ext in extensions: 8027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ext.extension_def() + '\n' 8037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Add checks for numeric limits 8057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if messages: 8067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen count_required_fields = lambda m: len([f for f in msg.fields if f.rules == 'REQUIRED']) 8077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen largest_msg = max(messages, key = count_required_fields) 8087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen largest_count = count_required_fields(largest_msg) 8097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if largest_count > 64: 8107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n/* Check that missing required fields will be properly detected */\n' 8117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#if PB_MAX_REQUIRED_FIELDS < %d\n' % largest_count 8127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#error Properly detecting missing required fields in %s requires \\\n' % largest_msg.name 8137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' setting PB_MAX_REQUIRED_FIELDS to %d or more.\n' % largest_count 8147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#endif\n' 8157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen worst = 0 8177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen worst_field = '' 8187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen checks = [] 8197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen checks_msgnames = [] 8207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in messages: 8217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen checks_msgnames.append(msg.name) 8227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in msg.fields: 8237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen status = field.largest_field_value() 8247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if isinstance(status, (str, unicode)): 8257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen checks.append(status) 8267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif status > worst: 8277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen worst = status 8287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen worst_field = str(field.struct_name) + '.' + str(field.name) 8297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if worst > 255 or checks: 8317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n/* Check that field information fits in pb_field_t */\n' 8327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if worst > 65535 or checks: 8347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#if !defined(PB_FIELD_32BIT)\n' 8357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if worst > 65535: 8367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#error Field descriptor for %s is too large. Define PB_FIELD_32BIT to fix this.\n' % worst_field 8377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 8387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen assertion = ' && '.join(str(c) + ' < 65536' for c in checks) 8397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen msgs = '_'.join(str(n) for n in checks_msgnames) 8407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* If you get an error here, it means that you need to define PB_FIELD_32BIT\n' 8417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * compile-time option. You can do that in pb.h or on compiler command line.\n' 8427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * \n' 8437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * The reason you need to do this is that some of your messages contain tag\n' 8447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * numbers or field sizes that are larger than what can fit in 8 or 16 bit\n' 8457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * field descriptors.\n' 8467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' */\n' 8477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) 8487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#endif\n\n' 8497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if worst < 65536: 8517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)\n' 8527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if worst > 255: 8537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#error Field descriptor for %s is too large. Define PB_FIELD_16BIT to fix this.\n' % worst_field 8547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 8557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen assertion = ' && '.join(str(c) + ' < 256' for c in checks) 8567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen msgs = '_'.join(str(n) for n in checks_msgnames) 8577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* If you get an error here, it means that you need to define PB_FIELD_16BIT\n' 8587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * compile-time option. You can do that in pb.h or on compiler command line.\n' 8597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * \n' 8607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * The reason you need to do this is that some of your messages contain tag\n' 8617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * numbers or field sizes that are larger than what can fit in the default\n' 8627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * 8 bit descriptors.\n' 8637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' */\n' 8647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs) 8657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '#endif\n\n' 8667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Add check for sizeof(double) 8687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen has_double = False 8697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for msg in messages: 8707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for field in msg.fields: 8717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if field.ctype == 'double': 8727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen has_double = True 8737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if has_double: 8757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 8767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '/* On some platforms (such as AVR), double is really float.\n' 8777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * These are not directly supported by nanopb, but see example_avr_double.\n' 8787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' * To get rid of this error, remove any double fields from your .proto.\n' 8797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield ' */\n' 8807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield 'STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n' 8817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen yield '\n' 8837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 8857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Options parsing for the .proto files 8867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 8877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenfrom fnmatch import fnmatch 8897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 8907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef read_options_file(infile): 8917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Parse a separate options file to list: 8927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen [(namemask, options), ...] 8937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 8947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen results = [] 8957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for line in infile: 8967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen line = line.strip() 8977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not line or line.startswith('//') or line.startswith('#'): 8987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen continue 8997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen parts = line.split(None, 1) 9017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen opts = nanopb_pb2.NanoPBOptions() 9027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen text_format.Merge(parts[1], opts) 9037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen results.append((parts[0], opts)) 9047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return results 9067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass Globals: 9087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Ugly global variables, should find a good way to pass these.''' 9097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen verbose_options = False 9107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen separate_options = [] 9117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen matched_namemasks = set() 9127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef get_nanopb_suboptions(subdesc, options, name): 9147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Get copy of options, and merge information from subdesc.''' 9157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen new_options = nanopb_pb2.NanoPBOptions() 9167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen new_options.CopyFrom(options) 9177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Handle options defined in a separate file 9197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen dotname = '.'.join(name.parts) 9207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for namemask, options in Globals.separate_options: 9217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if fnmatch(dotname, namemask): 9227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Globals.matched_namemasks.add(namemask) 9237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen new_options.MergeFrom(options) 9247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Handle options defined in .proto 9267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if isinstance(subdesc.options, descriptor.FieldOptions): 9277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ext_type = nanopb_pb2.nanopb 9287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif isinstance(subdesc.options, descriptor.FileOptions): 9297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ext_type = nanopb_pb2.nanopb_fileopt 9307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif isinstance(subdesc.options, descriptor.MessageOptions): 9317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ext_type = nanopb_pb2.nanopb_msgopt 9327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen elif isinstance(subdesc.options, descriptor.EnumOptions): 9337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ext_type = nanopb_pb2.nanopb_enumopt 9347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 9357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise Exception("Unknown options type") 9367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if subdesc.options.HasExtension(ext_type): 9387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ext = subdesc.options.Extensions[ext_type] 9397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen new_options.MergeFrom(ext) 9407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if Globals.verbose_options: 9427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write("Options for " + dotname + ": ") 9437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write(text_format.MessageToString(new_options) + "\n") 9447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return new_options 9467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 9497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Command line interface 9507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# --------------------------------------------------------------------------- 9517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport sys 9537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport os.path 9547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenfrom optparse import OptionParser 9557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser = OptionParser( 9577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen usage = "Usage: nanopb_generator.py [options] file.pb ...", 9587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen epilog = "Compile file.pb from file.proto by: 'protoc -ofile.pb file.proto'. " + 9597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen "Output will be written to file.pb.h and file.pb.c.") 9607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-x", dest="exclude", metavar="FILE", action="append", default=[], 9617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Exclude file from generated #include list.") 9627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-e", "--extension", dest="extension", metavar="EXTENSION", default="pb", 9637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Set extension to use instead of 'pb' for generated files. [default: %default]") 9647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-f", "--options-file", dest="options_file", metavar="FILE", default="%s.options", 9657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Set name of a separate generator options file.") 9667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-Q", "--generated-include-format", dest="genformat", 9677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen metavar="FORMAT", default='#include "%s"\n', 9687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Set format string to use for including other .pb.h files. [default: %default]") 9697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-L", "--library-include-format", dest="libformat", 9707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen metavar="FORMAT", default='#include <%s>\n', 9717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Set format string to use for including the nanopb pb.h header. [default: %default]") 9727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-T", "--no-timestamp", dest="notimestamp", action="store_true", default=False, 9737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Don't add timestamp to .pb.h and .pb.c preambles") 9747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, 9757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Don't print anything except errors.") 9767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, 9777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Print more information.") 9787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenoptparser.add_option("-s", dest="settings", metavar="OPTION:VALUE", action="append", default=[], 9797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen help="Set generator option (max_size, max_count etc.).") 9807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef process_file(filename, fdesc, options): 9827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Process a single file. 9837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen filename: The full path to the .proto or .pb source file, as string. 9847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen fdesc: The loaded FileDescriptorSet, or None to read from the input file. 9857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen options: Command line options as they come from OptionsParser. 9867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Returns a dict: 9887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen {'headername': Name of header file, 9897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 'headerdata': Data for the .h header file, 9907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 'sourcename': Name of the source code file, 9917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 'sourcedata': Data for the .c source code file 9927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 9937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ''' 9947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen toplevel_options = nanopb_pb2.NanoPBOptions() 9957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for s in options.settings: 9967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen text_format.Merge(s, toplevel_options) 9977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 9987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not fdesc: 9997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen data = open(filename, 'rb').read() 10007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen fdesc = descriptor.FileDescriptorSet.FromString(data).file[0] 10017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Check if there is a separate .options file 10037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen try: 10047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen optfilename = options.options_file % os.path.splitext(filename)[0] 10057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen except TypeError: 10067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # No %s specified, use the filename as-is 10077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen optfilename = options.options_file 10087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if os.path.isfile(optfilename): 10107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if options.verbose: 10117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write('Reading options from ' + optfilename + '\n') 10127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Globals.separate_options = read_options_file(open(optfilename, "rU")) 10147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 10157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Globals.separate_options = [] 10167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Globals.matched_namemasks = set() 10177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Parse the file 10197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename])) 10207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen enums, messages, extensions = parse_file(fdesc, file_options) 10217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Decide the file names 10237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen noext = os.path.splitext(filename)[0] 10247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen headername = noext + '.' + options.extension + '.h' 10257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sourcename = noext + '.' + options.extension + '.c' 10267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen headerbasename = os.path.basename(headername) 10277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # List of .proto files that should not be included in the C header file 10297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # even if they are mentioned in the source .proto. 10307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto'] + options.exclude 10317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen dependencies = [d for d in fdesc.dependency if d not in excludes] 10327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen headerdata = ''.join(generate_header(dependencies, headerbasename, enums, 10347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen messages, extensions, options)) 10357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sourcedata = ''.join(generate_source(headerbasename, enums, 10377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen messages, extensions, options)) 10387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Check if there were any lines in .options that did not match a member 10407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen unmatched = [n for n,o in Globals.separate_options if n not in Globals.matched_namemasks] 10417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if unmatched and not options.quiet: 10427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write("Following patterns in " + optfilename + " did not match any fields: " 10437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen + ', '.join(unmatched) + "\n") 10447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not Globals.verbose_options: 10457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write("Use protoc --nanopb-out=-v:. to see a list of the field names.\n") 10467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return {'headername': headername, 'headerdata': headerdata, 10487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 'sourcename': sourcename, 'sourcedata': sourcedata} 10497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef main_cli(): 10517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Main function when invoked directly from the command line.''' 10527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen options, filenames = optparser.parse_args() 10547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not filenames: 10567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen optparser.print_help() 10577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.exit(1) 10587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if options.quiet: 10607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen options.verbose = False 10617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Globals.verbose_options = options.verbose 10637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for filename in filenames: 10657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen results = process_file(filename, None, options) 10667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if not options.quiet: 10687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stderr.write("Writing to " + results['headername'] + " and " 10697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen + results['sourcename'] + "\n") 10707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen open(results['headername'], 'w').write(results['headerdata']) 10727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen open(results['sourcename'], 'w').write(results['sourcedata']) 10737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef main_plugin(): 10757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Main function when invoked as a protoc plugin.''' 10767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import sys 10787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if sys.platform == "win32": 10797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import os, msvcrt 10807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Set stdin and stdout to binary mode 10817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) 10827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) 10837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen data = sys.stdin.read() 10857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen request = plugin_pb2.CodeGeneratorRequest.FromString(data) 10867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen import shlex 10887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen args = shlex.split(request.parameter) 10897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen options, dummy = optparser.parse_args(args) 10907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen Globals.verbose_options = options.verbose 10927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen response = plugin_pb2.CodeGeneratorResponse() 10947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 10957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for filename in request.file_to_generate: 10967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for fdesc in request.proto_file: 10977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if fdesc.name == filename: 10987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen results = process_file(filename, fdesc, options) 10997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen f = response.file.add() 11017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen f.name = results['headername'] 11027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen f.content = results['headerdata'] 11037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen f = response.file.add() 11057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen f.name = results['sourcename'] 11067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen f.content = results['sourcedata'] 11077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen sys.stdout.write(response.SerializeToString()) 11097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 11107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenif __name__ == '__main__': 11117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Check if we are running as a plugin under protoc 11127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if 'protoc-gen-' in sys.argv[0] or '--protoc-plugin' in sys.argv: 11137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen main_plugin() 11147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 11157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen main_cli() 11167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1117