X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=generator%2Fnanopb_generator.py;h=2b1d63e5c6f6a0e031e6fecd7a9909dda3f48355;hb=708084e7883a95dd7fd315cdc909f6664491c043;hp=0d7be492c9db389c6a65210bccdefcf1ebd04cdb;hpb=8d12fecc7e4fb6899eb0d013abe0d6a5e03447ce;p=apps%2Fagl-service-can-low-level.git diff --git a/generator/nanopb_generator.py b/generator/nanopb_generator.py index 0d7be492..2b1d63e5 100755 --- a/generator/nanopb_generator.py +++ b/generator/nanopb_generator.py @@ -1,9 +1,10 @@ #!/usr/bin/python '''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.''' -nanopb_version = "nanopb-0.3.2-dev" +nanopb_version = "nanopb-0.3.4-dev" import sys +import re try: # Add some dummy imports to keep packaging tools happy. @@ -159,11 +160,30 @@ class Enum: self.values = [(names + x.name, x.number) for x in desc.value] self.value_longnames = [self.names + x.name for x in desc.value] + self.packed = enum_options.packed_enum + + def has_negative(self): + for n, v in self.values: + if v < 0: + return True + return False def __str__(self): result = 'typedef enum _%s {\n' % self.names result += ',\n'.join([" %s = %d" % x for x in self.values]) - result += '\n} %s;' % self.names + result += '\n}' + + if self.packed: + result += ' pb_packed' + + result += ' %s;' % self.names + + if not self.options.long_names: + # Define the long names always so that enum value references + # from other files work properly. + for i, x in enumerate(self.values): + result += '\n#define %s %s' % (self.value_longnames[i], x[0]) + return result class Field: @@ -328,7 +348,7 @@ class Field: inner_init = '""' elif self.pbtype == 'BYTES': inner_init = '{0, {0}}' - elif self.pbtype == 'ENUM': + elif self.pbtype in ('ENUM', 'UENUM'): inner_init = '(%s)0' % self.ctype else: inner_init = '0' @@ -586,7 +606,11 @@ class OneOf(Field): self.struct_name = struct_name self.name = oneof_desc.name self.ctype = 'union' + self.pbtype = 'oneof' self.fields = [] + self.allocation = 'ONEOF' + self.default = None + self.rules = 'ONEOF' def add_field(self, field): if field.allocation == 'CALLBACK': @@ -633,7 +657,6 @@ class OneOf(Field): return '\n'.join([f.tags() for f in self.fields]) def pb_field_t(self, prev_field_name): - prev_field_name = prev_field_name or self.name result = ',\n'.join([f.pb_field_t(prev_field_name) for f in self.fields]) return result @@ -641,7 +664,17 @@ class OneOf(Field): return max([f.largest_field_value() for f in self.fields]) def encoded_size(self, allmsgs): - return max([f.encoded_size(allmsgs) for f in self.fields]) + largest = EncodedSize(0) + for f in self.fields: + size = f.encoded_size(allmsgs) + if size is None: + return None + elif size.symbols: + return None # Cannot resolve maximum of symbols + elif size.value > largest.value: + largest = size + + return largest # --------------------------------------------------------------------------- # Generation of messages (structures) @@ -655,6 +688,9 @@ class Message: self.oneofs = {} no_unions = [] + if message_options.msgid: + self.msgid = message_options.msgid + if hasattr(desc, 'oneof_decl'): for i, f in enumerate(desc.oneof_decl): oneof_options = get_nanopb_suboptions(desc, message_options, self.name + f.name) @@ -842,7 +878,7 @@ def parse_file(fdesc, file_options): if message_options.skip_message: continue - + messages.append(Message(names, message, message_options)) for enum in message.enum_type: enum_options = get_nanopb_suboptions(enum, message_options, names + enum.name) @@ -862,6 +898,14 @@ def parse_file(fdesc, file_options): idx = enum.value_longnames.index(field.default) field.default = enum.values[idx][0] + # Fix field data types where enums have negative values. + for enum in enums: + if not enum.has_negative(): + for message in messages: + for field in message.fields: + if field.pbtype == 'ENUM' and field.ctype == enum.names: + field.pbtype = 'UENUM' + return enums, messages, extensions def toposort2(data): @@ -989,7 +1033,35 @@ def generate_header(dependencies, headername, enums, messages, extensions, optio identifier = '%s_size' % msg.name yield '#define %-40s %s\n' % (identifier, msize) yield '\n' + + yield '/* Message IDs (where set with "msgid" option) */\n' + yield '#ifdef PB_MSGID\n' + for msg in messages: + if hasattr(msg,'msgid'): + yield '#define PB_MSG_%d %s\n' % (msg.msgid, msg.name) + yield '\n' + + symbol = make_identifier(headername.split('.')[0]) + yield '#define %s_MESSAGES \\\n' % symbol + + for msg in messages: + m = "-1" + msize = msg.encoded_size(messages) + if msize is not None: + m = msize + if hasattr(msg,'msgid'): + yield '\tPB_MSG(%d,%s,%s) \\\n' % (msg.msgid, m, msg.name) + yield '\n' + + for msg in messages: + if hasattr(msg,'msgid'): + yield '#define %s_msgid %d\n' % (msg.name, msg.msgid) + yield '\n' + + yield '#endif\n\n' + + yield '#ifdef __cplusplus\n' yield '} /* extern "C" */\n' yield '#endif\n' @@ -1114,14 +1186,32 @@ def read_options_file(infile): [(namemask, options), ...] ''' results = [] - for line in infile: + data = infile.read() + data = re.sub('/\*.*?\*/', '', data, flags = re.MULTILINE) + data = re.sub('//.*?$', '', data, flags = re.MULTILINE) + data = re.sub('#.*?$', '', data, flags = re.MULTILINE) + for i, line in enumerate(data.split('\n')): line = line.strip() - if not line or line.startswith('//') or line.startswith('#'): + if not line: continue parts = line.split(None, 1) + + if len(parts) < 2: + sys.stderr.write("%s:%d: " % (infile.name, i + 1) + + "Option lines should have space between field name and options. " + + "Skipping line: '%s'\n" % line) + continue + opts = nanopb_pb2.NanoPBOptions() - text_format.Merge(parts[1], opts) + + try: + text_format.Merge(parts[1], opts) + except Exception, e: + sys.stderr.write("%s:%d: " % (infile.name, i + 1) + + "Unparseable option line: '%s'. " % line + + "Error: %s\n" % str(e)) + continue results.append((parts[0], opts)) return results @@ -1315,8 +1405,15 @@ def main_plugin(): data = sys.stdin.read() request = plugin_pb2.CodeGeneratorRequest.FromString(data) + try: + # Versions of Python prior to 2.7.3 do not support unicode + # input to shlex.split(). Try to convert to str if possible. + params = str(request.parameter) + except UnicodeEncodeError: + params = request.parameter + import shlex - args = shlex.split(request.parameter) + args = shlex.split(params) options, dummy = optparser.parse_args(args) Globals.verbose_options = options.verbose