+# ---------------------------------------------------------------------------
+# Options parsing for the .proto files
+# ---------------------------------------------------------------------------
+
+from fnmatch import fnmatch
+
+def read_options_file(infile):
+ '''Parse a separate options file to list:
+ [(namemask, options), ...]
+ '''
+ results = []
+ for line in infile:
+ line = line.strip()
+ if not line or line.startswith('//') or line.startswith('#'):
+ continue
+
+ parts = line.split(None, 1)
+ opts = nanopb_pb2.NanoPBOptions()
+ text_format.Merge(parts[1], opts)
+ results.append((parts[0], opts))
+
+ return results
+
+class Globals:
+ '''Ugly global variables, should find a good way to pass these.'''
+ verbose_options = False
+ separate_options = []
+ matched_namemasks = set()
+
+def get_nanopb_suboptions(subdesc, options, name):
+ '''Get copy of options, and merge information from subdesc.'''
+ new_options = nanopb_pb2.NanoPBOptions()
+ new_options.CopyFrom(options)
+
+ # Handle options defined in a separate file
+ dotname = '.'.join(name.parts)
+ for namemask, options in Globals.separate_options:
+ if fnmatch(dotname, namemask):
+ Globals.matched_namemasks.add(namemask)
+ new_options.MergeFrom(options)
+
+ # Handle options defined in .proto
+ if isinstance(subdesc.options, descriptor.FieldOptions):
+ ext_type = nanopb_pb2.nanopb
+ elif isinstance(subdesc.options, descriptor.FileOptions):
+ ext_type = nanopb_pb2.nanopb_fileopt
+ elif isinstance(subdesc.options, descriptor.MessageOptions):
+ ext_type = nanopb_pb2.nanopb_msgopt
+ elif isinstance(subdesc.options, descriptor.EnumOptions):
+ ext_type = nanopb_pb2.nanopb_enumopt
+ else:
+ raise Exception("Unknown options type")
+
+ if subdesc.options.HasExtension(ext_type):
+ ext = subdesc.options.Extensions[ext_type]
+ new_options.MergeFrom(ext)
+
+ if Globals.verbose_options:
+ sys.stderr.write("Options for " + dotname + ": ")
+ sys.stderr.write(text_format.MessageToString(new_options) + "\n")
+
+ return new_options
+