+def process_file(filename, fdesc, options):
+ '''Process a single file.
+ filename: The full path to the .proto or .pb source file, as string.
+ fdesc: The loaded FileDescriptorSet, or None to read from the input file.
+ options: Command line options as they come from OptionsParser.
+
+ Returns a dict:
+ {'headername': Name of header file,
+ 'headerdata': Data for the .h header file,
+ 'sourcename': Name of the source code file,
+ 'sourcedata': Data for the .c source code file
+ }
+ '''
+ toplevel_options = nanopb_pb2.NanoPBOptions()
+ for s in options.settings:
+ text_format.Merge(s, toplevel_options)
+
+ if not fdesc:
+ data = open(filename, 'rb').read()
+ fdesc = descriptor.FileDescriptorSet.FromString(data).file[0]
+
+ # Check if there is a separate .options file
+ try:
+ optfilename = options.options_file % os.path.splitext(filename)[0]
+ except TypeError:
+ # No %s specified, use the filename as-is
+ optfilename = options.options_file
+
+ if os.path.isfile(optfilename):
+ if options.verbose:
+ sys.stderr.write('Reading options from ' + optfilename + '\n')
+
+ Globals.separate_options = read_options_file(open(optfilename, "rU"))
+ else:
+ Globals.separate_options = []
+ Globals.matched_namemasks = set()
+
+ # Parse the file
+ file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename]))
+ enums, messages, extensions = parse_file(fdesc, file_options)
+
+ # Decide the file names
+ noext = os.path.splitext(filename)[0]
+ headername = noext + '.' + options.extension + '.h'
+ sourcename = noext + '.' + options.extension + '.c'
+ headerbasename = os.path.basename(headername)
+
+ # List of .proto files that should not be included in the C header file
+ # even if they are mentioned in the source .proto.
+ excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto'] + options.exclude
+ dependencies = [d for d in fdesc.dependency if d not in excludes]
+
+ headerdata = ''.join(generate_header(dependencies, headerbasename, enums,
+ messages, extensions, options))
+
+ sourcedata = ''.join(generate_source(headerbasename, enums,
+ messages, extensions, options))
+
+ # Check if there were any lines in .options that did not match a member
+ unmatched = [n for n,o in Globals.separate_options if n not in Globals.matched_namemasks]
+ if unmatched and not options.quiet:
+ sys.stderr.write("Following patterns in " + optfilename + " did not match any fields: "
+ + ', '.join(unmatched) + "\n")
+ if not Globals.verbose_options:
+ sys.stderr.write("Use protoc --nanopb-out=-v:. to see a list of the field names.\n")
+
+ return {'headername': headername, 'headerdata': headerdata,
+ 'sourcename': sourcename, 'sourcedata': sourcedata}
+
+def main_cli():
+ '''Main function when invoked directly from the command line.'''
+
+ options, filenames = optparser.parse_args()