Compare commits
15 Commits
nanopb-0.1
...
nanopb-0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92bb37b074 | ||
|
|
ad9a885644 | ||
|
|
08391f35ee | ||
|
|
3aaa4ad8c2 | ||
|
|
db1eefc24b | ||
|
|
0ee4bb96b1 | ||
|
|
28b0136ea4 | ||
|
|
9e0ee92f0a | ||
|
|
c3fa362653 | ||
|
|
bffd3a9acc | ||
|
|
dcab39a41c | ||
|
|
900c8dd125 | ||
|
|
3f563792ad | ||
|
|
b214de4e1e | ||
|
|
be78e3b4d0 |
10
CHANGELOG
10
CHANGELOG
@@ -1,3 +1,13 @@
|
|||||||
|
nanopb-0.1.7 (not yet released)
|
||||||
|
Remove "skip" mode from pb_istream_t callbacks. Example implementation had a bug. (issue 37)
|
||||||
|
Add option to use shorter names for enum values (issue 38)
|
||||||
|
Improve options support in generator (issues 12, 30)
|
||||||
|
Add nanopb version number to generated files (issue 36)
|
||||||
|
Add extern "C" to generated headers (issue 35)
|
||||||
|
Add names for structs to allow forward declaration (issue 39)
|
||||||
|
Add buffer size check in example (issue 34)
|
||||||
|
Fix build warnings on MS compilers (issue 33)
|
||||||
|
|
||||||
nanopb-0.1.6
|
nanopb-0.1.6
|
||||||
Reorganize the field decoder interface (issue 2)
|
Reorganize the field decoder interface (issue 2)
|
||||||
Improve performance in submessage decoding (issue 28)
|
Improve performance in submessage decoding (issue 28)
|
||||||
|
|||||||
@@ -38,6 +38,20 @@ This file, in turn, requires the file *google/protobuf/descriptor.proto*. This i
|
|||||||
|
|
||||||
protoc -I/usr/include -Inanopb/generator -I. -omessage.pb message.proto
|
protoc -I/usr/include -Inanopb/generator -I. -omessage.pb message.proto
|
||||||
|
|
||||||
|
The options can be defined in file, message and field scopes::
|
||||||
|
|
||||||
|
option (nanopb_fileopt).max_size = 20; // File scope
|
||||||
|
message Message
|
||||||
|
{
|
||||||
|
option (nanopb_msgopt).max_size = 30; // Message scope
|
||||||
|
required string fieldsize = 1 [(nanopb).max_size = 40]; // Field scope
|
||||||
|
}
|
||||||
|
|
||||||
|
It is also possible to give the options on command line, but then they will affect the whole file. For example::
|
||||||
|
|
||||||
|
user@host:~$ python ../generator/nanopb_generator.py -s 'max_size: 20' message.pb
|
||||||
|
|
||||||
|
|
||||||
Streams
|
Streams
|
||||||
=======
|
=======
|
||||||
|
|
||||||
@@ -92,9 +106,8 @@ Writing to stdout::
|
|||||||
|
|
||||||
Input streams
|
Input streams
|
||||||
-------------
|
-------------
|
||||||
For input streams, there are a few extra rules:
|
For input streams, there is one extra rule:
|
||||||
|
|
||||||
#) If buf is NULL, read from stream but don't store the data. This is used to skip unknown input.
|
|
||||||
#) You don't need to know the length of the message in advance. After getting EOF error when reading, set bytes_left to 0 and return false. Pb_decode will detect this and if the EOF was in a proper position, it will return true.
|
#) You don't need to know the length of the message in advance. After getting EOF error when reading, set bytes_left to 0 and return false. Pb_decode will detect this and if the EOF was in a proper position, it will return true.
|
||||||
|
|
||||||
Here is the structure::
|
Here is the structure::
|
||||||
|
|||||||
@@ -19,15 +19,6 @@ static bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
|
|||||||
int fd = (intptr_t)stream->state;
|
int fd = (intptr_t)stream->state;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (buf == NULL)
|
|
||||||
{
|
|
||||||
/* Well, this is a really inefficient way to skip input. */
|
|
||||||
/* It is only used when there are unknown fields. */
|
|
||||||
char dummy;
|
|
||||||
while (count-- && recv(fd, &dummy, 1, 0) == 1);
|
|
||||||
return count == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = recv(fd, buf, count, MSG_WAITALL);
|
result = recv(fd, buf, count, MSG_WAITALL);
|
||||||
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
|
|||||||
@@ -7,9 +7,24 @@
|
|||||||
|
|
||||||
import "google/protobuf/descriptor.proto";
|
import "google/protobuf/descriptor.proto";
|
||||||
|
|
||||||
|
enum FieldType {
|
||||||
|
FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible.
|
||||||
|
FT_CALLBACK = 1; // Always generate a callback field.
|
||||||
|
FT_STATIC = 2; // Generate a static field or raise an exception if not possible.
|
||||||
|
}
|
||||||
|
|
||||||
message NanoPBOptions {
|
message NanoPBOptions {
|
||||||
|
// Allocated size for 'bytes' and 'string' fields.
|
||||||
optional int32 max_size = 1;
|
optional int32 max_size = 1;
|
||||||
|
|
||||||
|
// Allocated number of entries in arrays ('repeated' fields)
|
||||||
optional int32 max_count = 2;
|
optional int32 max_count = 2;
|
||||||
|
|
||||||
|
// Force type of field (callback or static allocation)
|
||||||
|
optional FieldType type = 3 [default = FT_DEFAULT];
|
||||||
|
|
||||||
|
// Use long names for enums, i.e. EnumName_EnumValue.
|
||||||
|
optional bool long_names = 4 [default = true];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protocol Buffers extension number registry
|
// Protocol Buffers extension number registry
|
||||||
@@ -20,7 +35,20 @@ message NanoPBOptions {
|
|||||||
// Extensions: 1010 (all types)
|
// Extensions: 1010 (all types)
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
|
||||||
|
extend google.protobuf.FileOptions {
|
||||||
|
optional NanoPBOptions nanopb_fileopt = 1010;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend google.protobuf.MessageOptions {
|
||||||
|
optional NanoPBOptions nanopb_msgopt = 1010;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend google.protobuf.EnumOptions {
|
||||||
|
optional NanoPBOptions nanopb_enumopt = 1010;
|
||||||
|
}
|
||||||
|
|
||||||
extend google.protobuf.FieldOptions {
|
extend google.protobuf.FieldOptions {
|
||||||
optional NanoPBOptions nanopb = 1010;
|
optional NanoPBOptions nanopb = 1010;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
|
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
|
||||||
|
nanopb_version = "nanopb-0.1.7"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import google.protobuf.descriptor_pb2 as descriptor
|
import google.protobuf.descriptor_pb2 as descriptor
|
||||||
@@ -22,6 +23,16 @@ except:
|
|||||||
print
|
print
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Generation of single fields
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import time
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
# Values are tuple (c type, pb ltype)
|
# Values are tuple (c type, pb ltype)
|
||||||
@@ -69,19 +80,24 @@ def names_from_type_name(type_name):
|
|||||||
return Names(type_name[1:].split('.'))
|
return Names(type_name[1:].split('.'))
|
||||||
|
|
||||||
class Enum:
|
class Enum:
|
||||||
def __init__(self, names, desc):
|
def __init__(self, names, desc, enum_options):
|
||||||
'''desc is EnumDescriptorProto'''
|
'''desc is EnumDescriptorProto'''
|
||||||
self.names = names + desc.name
|
|
||||||
|
if enum_options.long_names:
|
||||||
|
self.names = names + desc.name
|
||||||
|
else:
|
||||||
|
self.names = names
|
||||||
|
|
||||||
self.values = [(self.names + x.name, x.number) for x in desc.value]
|
self.values = [(self.names + x.name, x.number) for x in desc.value]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
result = 'typedef enum {\n'
|
result = 'typedef enum _%s {\n' % self.names
|
||||||
result += ',\n'.join([" %s = %d" % x for x in self.values])
|
result += ',\n'.join([" %s = %d" % x for x in self.values])
|
||||||
result += '\n} %s;' % self.names
|
result += '\n} %s;' % self.names
|
||||||
return result
|
return result
|
||||||
|
|
||||||
class Field:
|
class Field:
|
||||||
def __init__(self, struct_name, desc):
|
def __init__(self, struct_name, desc, field_options):
|
||||||
'''desc is FieldDescriptorProto'''
|
'''desc is FieldDescriptorProto'''
|
||||||
self.tag = desc.number
|
self.tag = desc.number
|
||||||
self.struct_name = struct_name
|
self.struct_name = struct_name
|
||||||
@@ -91,28 +107,27 @@ class Field:
|
|||||||
self.max_count = None
|
self.max_count = None
|
||||||
self.array_decl = ""
|
self.array_decl = ""
|
||||||
|
|
||||||
# Parse nanopb-specific field options
|
# Parse field options
|
||||||
if desc.options.HasExtension(nanopb_pb2.nanopb):
|
if field_options.HasField("max_size"):
|
||||||
ext = desc.options.Extensions[nanopb_pb2.nanopb]
|
self.max_size = field_options.max_size
|
||||||
if ext.HasField("max_size"):
|
|
||||||
self.max_size = ext.max_size
|
if field_options.HasField("max_count"):
|
||||||
if ext.HasField("max_count"):
|
self.max_count = field_options.max_count
|
||||||
self.max_count = ext.max_count
|
|
||||||
|
|
||||||
if desc.HasField('default_value'):
|
if desc.HasField('default_value'):
|
||||||
self.default = desc.default_value
|
self.default = desc.default_value
|
||||||
|
|
||||||
# Decide HTYPE
|
# Decide HTYPE
|
||||||
# HTYPE is the high-order nibble of nanopb field description,
|
# HTYPE is the high-order nibble of nanopb field description,
|
||||||
# defining whether value is required/optional/repeated.
|
# defining whether value is required/optional/repeated.
|
||||||
is_callback = False
|
can_be_static = True
|
||||||
if desc.label == FieldD.LABEL_REQUIRED:
|
if desc.label == FieldD.LABEL_REQUIRED:
|
||||||
self.htype = 'PB_HTYPE_REQUIRED'
|
self.htype = 'PB_HTYPE_REQUIRED'
|
||||||
elif desc.label == FieldD.LABEL_OPTIONAL:
|
elif desc.label == FieldD.LABEL_OPTIONAL:
|
||||||
self.htype = 'PB_HTYPE_OPTIONAL'
|
self.htype = 'PB_HTYPE_OPTIONAL'
|
||||||
elif desc.label == FieldD.LABEL_REPEATED:
|
elif desc.label == FieldD.LABEL_REPEATED:
|
||||||
if self.max_count is None:
|
if self.max_count is None:
|
||||||
is_callback = True
|
can_be_static = False
|
||||||
else:
|
else:
|
||||||
self.htype = 'PB_HTYPE_ARRAY'
|
self.htype = 'PB_HTYPE_ARRAY'
|
||||||
self.array_decl = '[%d]' % self.max_count
|
self.array_decl = '[%d]' % self.max_count
|
||||||
@@ -133,14 +148,14 @@ class Field:
|
|||||||
elif desc.type == FieldD.TYPE_STRING:
|
elif desc.type == FieldD.TYPE_STRING:
|
||||||
self.ltype = 'PB_LTYPE_STRING'
|
self.ltype = 'PB_LTYPE_STRING'
|
||||||
if self.max_size is None:
|
if self.max_size is None:
|
||||||
is_callback = True
|
can_be_static = False
|
||||||
else:
|
else:
|
||||||
self.ctype = 'char'
|
self.ctype = 'char'
|
||||||
self.array_decl += '[%d]' % self.max_size
|
self.array_decl += '[%d]' % self.max_size
|
||||||
elif desc.type == FieldD.TYPE_BYTES:
|
elif desc.type == FieldD.TYPE_BYTES:
|
||||||
self.ltype = 'PB_LTYPE_BYTES'
|
self.ltype = 'PB_LTYPE_BYTES'
|
||||||
if self.max_size is None:
|
if self.max_size is None:
|
||||||
is_callback = True
|
can_be_static = False
|
||||||
else:
|
else:
|
||||||
self.ctype = self.struct_name + self.name + 't'
|
self.ctype = self.struct_name + self.name + 't'
|
||||||
elif desc.type == FieldD.TYPE_MESSAGE:
|
elif desc.type == FieldD.TYPE_MESSAGE:
|
||||||
@@ -149,7 +164,16 @@ class Field:
|
|||||||
else:
|
else:
|
||||||
raise NotImplementedError(desc.type)
|
raise NotImplementedError(desc.type)
|
||||||
|
|
||||||
if is_callback:
|
if field_options.type == nanopb_pb2.FT_DEFAULT:
|
||||||
|
if can_be_static:
|
||||||
|
field_options.type = nanopb_pb2.FT_STATIC
|
||||||
|
else:
|
||||||
|
field_options.type = nanopb_pb2.FT_CALLBACK
|
||||||
|
|
||||||
|
if field_options.type == nanopb_pb2.FT_STATIC and not can_be_static:
|
||||||
|
raise Exception("Field %s is defined as static, but max_size or max_count is not given." % self.name)
|
||||||
|
|
||||||
|
if field_options.type == nanopb_pb2.FT_CALLBACK:
|
||||||
self.htype = 'PB_HTYPE_CALLBACK'
|
self.htype = 'PB_HTYPE_CALLBACK'
|
||||||
self.ctype = 'pb_callback_t'
|
self.ctype = 'pb_callback_t'
|
||||||
self.array_decl = ''
|
self.array_decl = ''
|
||||||
@@ -264,10 +288,19 @@ class Field:
|
|||||||
return max(self.tag, self.max_size, self.max_count)
|
return max(self.tag, self.max_size, self.max_count)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Generation of messages (structures)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class Message:
|
class Message:
|
||||||
def __init__(self, names, desc):
|
def __init__(self, names, desc, message_options):
|
||||||
self.name = names
|
self.name = names
|
||||||
self.fields = [Field(self.name, f) for f in desc.field]
|
self.fields = [Field(self.name, f, get_nanopb_suboptions(f, message_options)) for f in desc.field]
|
||||||
self.ordered_fields = self.fields[:]
|
self.ordered_fields = self.fields[:]
|
||||||
self.ordered_fields.sort()
|
self.ordered_fields.sort()
|
||||||
|
|
||||||
@@ -276,7 +309,7 @@ class Message:
|
|||||||
return [str(field.ctype) for field in self.fields]
|
return [str(field.ctype) for field in self.fields]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
result = 'typedef struct {\n'
|
result = 'typedef struct _%s {\n' % self.name
|
||||||
result += '\n'.join([str(f) for f in self.ordered_fields])
|
result += '\n'.join([str(f) for f in self.ordered_fields])
|
||||||
result += '\n} %s;' % self.name
|
result += '\n} %s;' % self.name
|
||||||
return result
|
return result
|
||||||
@@ -313,6 +346,16 @@ class Message:
|
|||||||
result += ' PB_LAST_FIELD\n};'
|
result += ' PB_LAST_FIELD\n};'
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Processing of entire .proto files
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def iterate_messages(desc, names = Names()):
|
def iterate_messages(desc, names = Names()):
|
||||||
'''Recursively find all messages. For each, yield name, DescriptorProto.'''
|
'''Recursively find all messages. For each, yield name, DescriptorProto.'''
|
||||||
if hasattr(desc, 'message_type'):
|
if hasattr(desc, 'message_type'):
|
||||||
@@ -327,7 +370,7 @@ def iterate_messages(desc, names = Names()):
|
|||||||
for x in iterate_messages(submsg, sub_names):
|
for x in iterate_messages(submsg, sub_names):
|
||||||
yield x
|
yield x
|
||||||
|
|
||||||
def parse_file(fdesc):
|
def parse_file(fdesc, file_options):
|
||||||
'''Takes a FileDescriptorProto and returns tuple (enum, messages).'''
|
'''Takes a FileDescriptorProto and returns tuple (enum, messages).'''
|
||||||
|
|
||||||
enums = []
|
enums = []
|
||||||
@@ -339,12 +382,14 @@ def parse_file(fdesc):
|
|||||||
base_name = Names()
|
base_name = Names()
|
||||||
|
|
||||||
for enum in fdesc.enum_type:
|
for enum in fdesc.enum_type:
|
||||||
enums.append(Enum(base_name, enum))
|
enum_options = get_nanopb_suboptions(enum, file_options)
|
||||||
|
enums.append(Enum(base_name, enum, enum_options))
|
||||||
|
|
||||||
for names, message in iterate_messages(fdesc, base_name):
|
for names, message in iterate_messages(fdesc, base_name):
|
||||||
messages.append(Message(names, message))
|
message_options = get_nanopb_suboptions(message, file_options)
|
||||||
|
messages.append(Message(names, message, message_options))
|
||||||
for enum in message.enum_type:
|
for enum in message.enum_type:
|
||||||
enums.append(Enum(names, enum))
|
enums.append(Enum(names, enum, message_options))
|
||||||
|
|
||||||
return enums, messages
|
return enums, messages
|
||||||
|
|
||||||
@@ -385,6 +430,7 @@ def generate_header(dependencies, headername, enums, messages):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
yield '/* Automatically generated nanopb header */\n'
|
yield '/* Automatically generated nanopb header */\n'
|
||||||
|
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
|
||||||
|
|
||||||
symbol = headername.replace('.', '_').upper()
|
symbol = headername.replace('.', '_').upper()
|
||||||
yield '#ifndef _PB_%s_\n' % symbol
|
yield '#ifndef _PB_%s_\n' % symbol
|
||||||
@@ -394,7 +440,10 @@ def generate_header(dependencies, headername, enums, messages):
|
|||||||
for dependency in dependencies:
|
for dependency in dependencies:
|
||||||
noext = os.path.splitext(dependency)[0]
|
noext = os.path.splitext(dependency)[0]
|
||||||
yield '#include "%s.pb.h"\n' % noext
|
yield '#include "%s.pb.h"\n' % noext
|
||||||
yield '\n'
|
|
||||||
|
yield '#ifdef __cplusplus\n'
|
||||||
|
yield 'extern "C" {\n'
|
||||||
|
yield '#endif\n\n'
|
||||||
|
|
||||||
yield '/* Enum definitions */\n'
|
yield '/* Enum definitions */\n'
|
||||||
for enum in enums:
|
for enum in enums:
|
||||||
@@ -458,6 +507,10 @@ def generate_header(dependencies, headername, enums, messages):
|
|||||||
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT)\n' % assertion
|
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT)\n' % assertion
|
||||||
yield '#endif\n'
|
yield '#endif\n'
|
||||||
|
|
||||||
|
yield '\n#ifdef __cplusplus\n'
|
||||||
|
yield '} /* extern "C" */\n'
|
||||||
|
yield '#endif\n'
|
||||||
|
|
||||||
# End of header
|
# End of header
|
||||||
yield '\n#endif\n'
|
yield '\n#endif\n'
|
||||||
|
|
||||||
@@ -465,6 +518,7 @@ def generate_source(headername, enums, messages):
|
|||||||
'''Generate content for a source file.'''
|
'''Generate content for a source file.'''
|
||||||
|
|
||||||
yield '/* Automatically generated nanopb constant definitions */\n'
|
yield '/* Automatically generated nanopb constant definitions */\n'
|
||||||
|
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
|
||||||
yield '#include "%s"\n\n' % headername
|
yield '#include "%s"\n\n' % headername
|
||||||
|
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
@@ -475,39 +529,105 @@ def generate_source(headername, enums, messages):
|
|||||||
for msg in messages:
|
for msg in messages:
|
||||||
yield msg.fields_definition() + '\n\n'
|
yield msg.fields_definition() + '\n\n'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
import os.path
|
# ---------------------------------------------------------------------------
|
||||||
|
# Command line interface
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
from optparse import OptionParser
|
||||||
|
import google.protobuf.text_format as text_format
|
||||||
|
|
||||||
|
optparser = OptionParser(
|
||||||
|
usage = "Usage: nanopb_generator.py [options] file.pb ...",
|
||||||
|
epilog = "Compile file.pb from file.proto by: 'protoc -ofile.pb file.proto'. " +
|
||||||
|
"Output will be written to file.pb.h and file.pb.c.")
|
||||||
|
optparser.add_option("-x", dest="exclude", metavar="FILE", action="append", default=[],
|
||||||
|
help="Exclude file from generated #include list.")
|
||||||
|
optparser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False,
|
||||||
|
help="Don't print anything except errors.")
|
||||||
|
optparser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
|
||||||
|
help="Print more information.")
|
||||||
|
optparser.add_option("-s", dest="settings", metavar="OPTION:VALUE", action="append", default=[],
|
||||||
|
help="Set generator option (max_size, max_count etc.).")
|
||||||
|
|
||||||
|
def get_nanopb_suboptions(subdesc, options):
|
||||||
|
'''Get copy of options, and merge information from subdesc.'''
|
||||||
|
new_options = nanopb_pb2.NanoPBOptions()
|
||||||
|
new_options.CopyFrom(options)
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if isinstance(subdesc.options, descriptor.FieldOptions):
|
||||||
print "Usage: " + sys.argv[0] + " file.pb"
|
ext_type = nanopb_pb2.nanopb
|
||||||
print "where file.pb has been compiled from .proto by:"
|
elif isinstance(subdesc.options, descriptor.FileOptions):
|
||||||
print "protoc -ofile.pb file.proto"
|
ext_type = nanopb_pb2.nanopb_fileopt
|
||||||
print "Output fill be written to file.pb.h and file.pb.c"
|
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)
|
||||||
|
|
||||||
|
return new_options
|
||||||
|
|
||||||
|
def process(filenames, options):
|
||||||
|
'''Process the files given on the command line.'''
|
||||||
|
|
||||||
|
if not filenames:
|
||||||
|
optparser.print_help()
|
||||||
|
return False
|
||||||
|
|
||||||
|
if options.quiet:
|
||||||
|
options.verbose = False
|
||||||
|
|
||||||
|
toplevel_options = nanopb_pb2.NanoPBOptions()
|
||||||
|
for s in options.settings:
|
||||||
|
text_format.Merge(s, toplevel_options)
|
||||||
|
|
||||||
|
for filename in filenames:
|
||||||
|
data = open(filename, 'rb').read()
|
||||||
|
fdesc = descriptor.FileDescriptorSet.FromString(data)
|
||||||
|
|
||||||
|
file_options = get_nanopb_suboptions(fdesc.file[0], toplevel_options)
|
||||||
|
|
||||||
|
if options.verbose:
|
||||||
|
print "Options for " + filename + ":"
|
||||||
|
print text_format.MessageToString(file_options)
|
||||||
|
|
||||||
|
enums, messages = parse_file(fdesc.file[0], file_options)
|
||||||
|
|
||||||
|
noext = os.path.splitext(filename)[0]
|
||||||
|
headername = noext + '.pb.h'
|
||||||
|
sourcename = noext + '.pb.c'
|
||||||
|
headerbasename = os.path.basename(headername)
|
||||||
|
|
||||||
|
if not options.quiet:
|
||||||
|
print "Writing to " + headername + " and " + sourcename
|
||||||
|
|
||||||
|
# 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.file[0].dependency if d not in excludes]
|
||||||
|
|
||||||
|
header = open(headername, 'w')
|
||||||
|
for part in generate_header(dependencies, headerbasename, enums, messages):
|
||||||
|
header.write(part)
|
||||||
|
|
||||||
|
source = open(sourcename, 'w')
|
||||||
|
for part in generate_source(headerbasename, enums, messages):
|
||||||
|
source.write(part)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
options, filenames = optparser.parse_args()
|
||||||
|
status = process(filenames, options)
|
||||||
|
|
||||||
|
if not status:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
data = open(sys.argv[1], 'rb').read()
|
|
||||||
fdesc = descriptor.FileDescriptorSet.FromString(data)
|
|
||||||
enums, messages = parse_file(fdesc.file[0])
|
|
||||||
|
|
||||||
noext = os.path.splitext(sys.argv[1])[0]
|
|
||||||
headername = noext + '.pb.h'
|
|
||||||
sourcename = noext + '.pb.c'
|
|
||||||
headerbasename = os.path.basename(headername)
|
|
||||||
|
|
||||||
print "Writing to " + headername + " and " + sourcename
|
|
||||||
|
|
||||||
# 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']
|
|
||||||
dependencies = [d for d in fdesc.file[0].dependency if d not in excludes]
|
|
||||||
|
|
||||||
header = open(headername, 'w')
|
|
||||||
for part in generate_header(dependencies, headerbasename, enums, messages):
|
|
||||||
header.write(part)
|
|
||||||
|
|
||||||
source = open(sourcename, 'w')
|
|
||||||
for part in generate_source(headerbasename, enums, messages):
|
|
||||||
source.write(part)
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,70 @@ from google.protobuf import descriptor_pb2
|
|||||||
# @@protoc_insertion_point(imports)
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
|
||||||
|
import google.protobuf.descriptor_pb2
|
||||||
|
|
||||||
DESCRIPTOR = descriptor.FileDescriptor(
|
DESCRIPTOR = descriptor.FileDescriptor(
|
||||||
name='nanopb.proto',
|
name='nanopb.proto',
|
||||||
package='',
|
package='',
|
||||||
serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"4\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions')
|
serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"t\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true*;\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\r\n\tFT_STATIC\x10\x02:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions')
|
||||||
|
|
||||||
|
_FIELDTYPE = descriptor.EnumDescriptor(
|
||||||
|
name='FieldType',
|
||||||
|
full_name='FieldType',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
descriptor.EnumValueDescriptor(
|
||||||
|
name='FT_DEFAULT', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
descriptor.EnumValueDescriptor(
|
||||||
|
name='FT_CALLBACK', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
descriptor.EnumValueDescriptor(
|
||||||
|
name='FT_STATIC', index=2, number=2,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=168,
|
||||||
|
serialized_end=227,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
FT_DEFAULT = 0
|
||||||
|
FT_CALLBACK = 1
|
||||||
|
FT_STATIC = 2
|
||||||
|
|
||||||
|
NANOPB_FILEOPT_FIELD_NUMBER = 1010
|
||||||
|
nanopb_fileopt = descriptor.FieldDescriptor(
|
||||||
|
name='nanopb_fileopt', full_name='nanopb_fileopt', index=0,
|
||||||
|
number=1010, type=11, cpp_type=10, label=1,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=True, extension_scope=None,
|
||||||
|
options=None)
|
||||||
|
NANOPB_MSGOPT_FIELD_NUMBER = 1010
|
||||||
|
nanopb_msgopt = descriptor.FieldDescriptor(
|
||||||
|
name='nanopb_msgopt', full_name='nanopb_msgopt', index=1,
|
||||||
|
number=1010, type=11, cpp_type=10, label=1,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=True, extension_scope=None,
|
||||||
|
options=None)
|
||||||
|
NANOPB_ENUMOPT_FIELD_NUMBER = 1010
|
||||||
|
nanopb_enumopt = descriptor.FieldDescriptor(
|
||||||
|
name='nanopb_enumopt', full_name='nanopb_enumopt', index=2,
|
||||||
|
number=1010, type=11, cpp_type=10, label=1,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=True, extension_scope=None,
|
||||||
|
options=None)
|
||||||
NANOPB_FIELD_NUMBER = 1010
|
NANOPB_FIELD_NUMBER = 1010
|
||||||
nanopb = descriptor.FieldDescriptor(
|
nanopb = descriptor.FieldDescriptor(
|
||||||
name='nanopb', full_name='nanopb', index=0,
|
name='nanopb', full_name='nanopb', index=3,
|
||||||
number=1010, type=11, cpp_type=10, label=1,
|
number=1010, type=11, cpp_type=10, label=1,
|
||||||
has_default_value=False, default_value=None,
|
has_default_value=False, default_value=None,
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
@@ -44,6 +99,20 @@ _NANOPBOPTIONS = descriptor.Descriptor(
|
|||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
options=None),
|
options=None),
|
||||||
|
descriptor.FieldDescriptor(
|
||||||
|
name='type', full_name='NanoPBOptions.type', index=2,
|
||||||
|
number=3, type=14, cpp_type=8, label=1,
|
||||||
|
has_default_value=True, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
descriptor.FieldDescriptor(
|
||||||
|
name='long_names', full_name='NanoPBOptions.long_names', index=3,
|
||||||
|
number=4, type=8, cpp_type=7, label=1,
|
||||||
|
has_default_value=True, default_value=True,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
],
|
],
|
||||||
extensions=[
|
extensions=[
|
||||||
],
|
],
|
||||||
@@ -54,11 +123,11 @@ _NANOPBOPTIONS = descriptor.Descriptor(
|
|||||||
is_extendable=False,
|
is_extendable=False,
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
serialized_start=50,
|
serialized_start=50,
|
||||||
serialized_end=102,
|
serialized_end=166,
|
||||||
)
|
)
|
||||||
|
|
||||||
import google.protobuf.descriptor_pb2
|
_NANOPBOPTIONS.fields_by_name['type'].enum_type = _FIELDTYPE
|
||||||
|
DESCRIPTOR.message_types_by_name['NanoPBOptions'] = _NANOPBOPTIONS
|
||||||
|
|
||||||
class NanoPBOptions(message.Message):
|
class NanoPBOptions(message.Message):
|
||||||
__metaclass__ = reflection.GeneratedProtocolMessageType
|
__metaclass__ = reflection.GeneratedProtocolMessageType
|
||||||
@@ -66,6 +135,12 @@ class NanoPBOptions(message.Message):
|
|||||||
|
|
||||||
# @@protoc_insertion_point(class_scope:NanoPBOptions)
|
# @@protoc_insertion_point(class_scope:NanoPBOptions)
|
||||||
|
|
||||||
|
nanopb_fileopt.message_type = _NANOPBOPTIONS
|
||||||
|
google.protobuf.descriptor_pb2.FileOptions.RegisterExtension(nanopb_fileopt)
|
||||||
|
nanopb_msgopt.message_type = _NANOPBOPTIONS
|
||||||
|
google.protobuf.descriptor_pb2.MessageOptions.RegisterExtension(nanopb_msgopt)
|
||||||
|
nanopb_enumopt.message_type = _NANOPBOPTIONS
|
||||||
|
google.protobuf.descriptor_pb2.EnumOptions.RegisterExtension(nanopb_enumopt)
|
||||||
nanopb.message_type = _NANOPBOPTIONS
|
nanopb.message_type = _NANOPBOPTIONS
|
||||||
google.protobuf.descriptor_pb2.FieldOptions.RegisterExtension(nanopb)
|
google.protobuf.descriptor_pb2.FieldOptions.RegisterExtension(nanopb)
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
17
pb.h
17
pb.h
@@ -6,6 +6,8 @@
|
|||||||
* see pb_encode.h or pb_decode.h
|
* see pb_encode.h or pb_decode.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define NANOPB_VERSION nanopb-0.1.7
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -75,6 +77,7 @@ typedef enum {
|
|||||||
|
|
||||||
/* Number of declared LTYPES */
|
/* Number of declared LTYPES */
|
||||||
PB_LTYPES_COUNT = 7,
|
PB_LTYPES_COUNT = 7,
|
||||||
|
PB_LTYPE_MASK = 0x0F,
|
||||||
|
|
||||||
/******************
|
/******************
|
||||||
* Modifier flags *
|
* Modifier flags *
|
||||||
@@ -95,11 +98,13 @@ typedef enum {
|
|||||||
* data_offset points to pb_callback_t structure.
|
* data_offset points to pb_callback_t structure.
|
||||||
* LTYPE should be 0 (it is ignored, but sometimes
|
* LTYPE should be 0 (it is ignored, but sometimes
|
||||||
* used to speculatively index an array). */
|
* used to speculatively index an array). */
|
||||||
PB_HTYPE_CALLBACK = 0x30
|
PB_HTYPE_CALLBACK = 0x30,
|
||||||
|
|
||||||
|
PB_HTYPE_MASK = 0xF0
|
||||||
} pb_packed pb_type_t;
|
} pb_packed pb_type_t;
|
||||||
|
|
||||||
#define PB_HTYPE(x) ((x) & 0xF0)
|
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
|
||||||
#define PB_LTYPE(x) ((x) & 0x0F)
|
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
|
||||||
|
|
||||||
/* This structure is used in auto-generated constants
|
/* This structure is used in auto-generated constants
|
||||||
* to specify struct fields.
|
* to specify struct fields.
|
||||||
@@ -145,10 +150,12 @@ struct _pb_field_t {
|
|||||||
* It has the number of bytes in the beginning, and after that an array.
|
* It has the number of bytes in the beginning, and after that an array.
|
||||||
* Note that actual structs used will have a different length of bytes array.
|
* Note that actual structs used will have a different length of bytes array.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
struct _pb_bytes_array_t {
|
||||||
size_t size;
|
size_t size;
|
||||||
uint8_t bytes[1];
|
uint8_t bytes[1];
|
||||||
} pb_bytes_array_t;
|
};
|
||||||
|
|
||||||
|
typedef struct _pb_bytes_array_t pb_bytes_array_t;
|
||||||
|
|
||||||
/* This structure is used for giving the callback function.
|
/* This structure is used for giving the callback function.
|
||||||
* It is stored in the message structure and filled in by the method that
|
* It is stored in the message structure and filled in by the method that
|
||||||
|
|||||||
55
pb_decode.c
55
pb_decode.c
@@ -36,18 +36,6 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
|
|||||||
* pb_istream *
|
* pb_istream *
|
||||||
**************/
|
**************/
|
||||||
|
|
||||||
bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
|
||||||
{
|
|
||||||
if (stream->bytes_left < count)
|
|
||||||
PB_RETURN_ERROR(stream, "end-of-stream");
|
|
||||||
|
|
||||||
if (!stream->callback(stream, buf, count))
|
|
||||||
PB_RETURN_ERROR(stream, "io error");
|
|
||||||
|
|
||||||
stream->bytes_left -= count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
||||||
{
|
{
|
||||||
uint8_t *source = (uint8_t*)stream->state;
|
uint8_t *source = (uint8_t*)stream->state;
|
||||||
@@ -59,6 +47,33 @@ static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t coun
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
||||||
|
{
|
||||||
|
if (buf == NULL && stream->callback != buf_read)
|
||||||
|
{
|
||||||
|
/* Skip input bytes */
|
||||||
|
uint8_t tmp[16];
|
||||||
|
while (count > 16)
|
||||||
|
{
|
||||||
|
if (!pb_read(stream, tmp, 16))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
count -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pb_read(stream, tmp, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->bytes_left < count)
|
||||||
|
PB_RETURN_ERROR(stream, "end-of-stream");
|
||||||
|
|
||||||
|
if (!stream->callback(stream, buf, count))
|
||||||
|
PB_RETURN_ERROR(stream, "io error");
|
||||||
|
|
||||||
|
stream->bytes_left -= count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
|
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
pb_istream_t stream;
|
pb_istream_t stream;
|
||||||
@@ -83,7 +98,7 @@ static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
|
|||||||
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
|
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
|
||||||
{
|
{
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
uint8_t bitpos = 0;
|
int bitpos = 0;
|
||||||
*dest = 0;
|
*dest = 0;
|
||||||
|
|
||||||
while (bitpos < 64 && pb_read(stream, &byte, 1))
|
while (bitpos < 64 && pb_read(stream, &byte, 1))
|
||||||
@@ -447,7 +462,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
|
|||||||
if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED
|
if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED
|
||||||
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
|
&& iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
|
||||||
{
|
{
|
||||||
fields_seen[iter.required_field_index >> 3] |= 1 << (iter.required_field_index & 7);
|
fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decode_field(stream, wire_type, &iter))
|
if (!decode_field(stream, wire_type, &iter))
|
||||||
@@ -483,9 +498,9 @@ bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (value & 1)
|
if (value & 1)
|
||||||
*dest = ~(value >> 1);
|
*dest = (int64_t)(~(value >> 1));
|
||||||
else
|
else
|
||||||
*dest = value >> 1;
|
*dest = (int64_t)(value >> 1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -539,9 +554,9 @@ bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, vo
|
|||||||
|
|
||||||
switch (field->data_size)
|
switch (field->data_size)
|
||||||
{
|
{
|
||||||
case 1: *(uint8_t*)dest = value; break;
|
case 1: *(uint8_t*)dest = (uint8_t)value; break;
|
||||||
case 2: *(uint16_t*)dest = value; break;
|
case 2: *(uint16_t*)dest = (uint16_t)value; break;
|
||||||
case 4: *(uint32_t*)dest = value; break;
|
case 4: *(uint32_t*)dest = (uint32_t)value; break;
|
||||||
case 8: *(uint64_t*)dest = value; break;
|
case 8: *(uint64_t*)dest = value; break;
|
||||||
default: PB_RETURN_ERROR(stream, "invalid data_size");
|
default: PB_RETURN_ERROR(stream, "invalid data_size");
|
||||||
}
|
}
|
||||||
@@ -556,7 +571,7 @@ bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, v
|
|||||||
|
|
||||||
switch (field->data_size)
|
switch (field->data_size)
|
||||||
{
|
{
|
||||||
case 4: *(int32_t*)dest = value; break;
|
case 4: *(int32_t*)dest = (int32_t)value; break;
|
||||||
case 8: *(int64_t*)dest = value; break;
|
case 8: *(int64_t*)dest = value; break;
|
||||||
default: PB_RETURN_ERROR(stream, "invalid data_size");
|
default: PB_RETURN_ERROR(stream, "invalid data_size");
|
||||||
}
|
}
|
||||||
|
|||||||
14
pb_decode.h
14
pb_decode.h
@@ -12,6 +12,10 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "pb.h"
|
#include "pb.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Lightweight input stream.
|
/* Lightweight input stream.
|
||||||
* You can provide a callback function for reading or use
|
* You can provide a callback function for reading or use
|
||||||
* pb_istream_from_buffer.
|
* pb_istream_from_buffer.
|
||||||
@@ -19,12 +23,10 @@
|
|||||||
* Rules for callback:
|
* Rules for callback:
|
||||||
* 1) Return false on IO errors. This will cause decoding to abort.
|
* 1) Return false on IO errors. This will cause decoding to abort.
|
||||||
*
|
*
|
||||||
* 2) If buf is NULL, read but don't store bytes ("skip input").
|
* 2) You can use state to store your own data (e.g. buffer pointer),
|
||||||
*
|
|
||||||
* 3) You can use state to store your own data (e.g. buffer pointer),
|
|
||||||
* and rely on pb_read to verify that no-body reads past bytes_left.
|
* and rely on pb_read to verify that no-body reads past bytes_left.
|
||||||
*
|
*
|
||||||
* 4) Your callback may be used with substreams, in which case bytes_left
|
* 3) Your callback may be used with substreams, in which case bytes_left
|
||||||
* is different than from the main stream. Don't use bytes_left to compute
|
* is different than from the main stream. Don't use bytes_left to compute
|
||||||
* any pointers.
|
* any pointers.
|
||||||
*/
|
*/
|
||||||
@@ -104,4 +106,8 @@ bool pb_skip_varint(pb_istream_t *stream);
|
|||||||
bool pb_skip_string(pb_istream_t *stream);
|
bool pb_skip_string(pb_istream_t *stream);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
10
pb_encode.c
10
pb_encode.c
@@ -205,7 +205,7 @@ bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], cons
|
|||||||
bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
|
bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
|
||||||
{
|
{
|
||||||
uint8_t buffer[10];
|
uint8_t buffer[10];
|
||||||
int i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
return pb_write(stream, (uint8_t*)&value, 1);
|
return pb_write(stream, (uint8_t*)&value, 1);
|
||||||
@@ -225,9 +225,9 @@ bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
|
|||||||
{
|
{
|
||||||
uint64_t zigzagged;
|
uint64_t zigzagged;
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
zigzagged = ~(value << 1);
|
zigzagged = (uint64_t)(~(value << 1));
|
||||||
else
|
else
|
||||||
zigzagged = value << 1;
|
zigzagged = (uint64_t)(value << 1);
|
||||||
|
|
||||||
return pb_encode_varint(stream, zigzagged);
|
return pb_encode_varint(stream, zigzagged);
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, int field_number)
|
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
|
||||||
{
|
{
|
||||||
uint64_t tag = wiretype | (field_number << 3);
|
uint64_t tag = wiretype | (field_number << 3);
|
||||||
return pb_encode_varint(stream, tag);
|
return pb_encode_varint(stream, tag);
|
||||||
@@ -370,7 +370,7 @@ bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, co
|
|||||||
|
|
||||||
bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
|
bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
|
||||||
{
|
{
|
||||||
uint64_t value = 0;
|
int64_t value = 0;
|
||||||
|
|
||||||
switch (field->data_size)
|
switch (field->data_size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,10 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "pb.h"
|
#include "pb.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Lightweight output stream.
|
/* Lightweight output stream.
|
||||||
* You can provide callback for writing or use pb_ostream_from_buffer.
|
* You can provide callback for writing or use pb_ostream_from_buffer.
|
||||||
*
|
*
|
||||||
@@ -54,7 +58,7 @@ bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field);
|
|||||||
|
|
||||||
/* Encode field header by manually specifing wire type. You need to use this if
|
/* Encode field header by manually specifing wire type. You need to use this if
|
||||||
* you want to write out packed arrays from a callback field. */
|
* you want to write out packed arrays from a callback field. */
|
||||||
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, int field_number);
|
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
|
||||||
|
|
||||||
/* Encode an integer in the varint format.
|
/* Encode an integer in the varint format.
|
||||||
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */
|
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */
|
||||||
@@ -99,5 +103,8 @@ bool pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *sr
|
|||||||
* instead, it has the same functionality with a less confusing interface. */
|
* instead, it has the same functionality with a less confusing interface. */
|
||||||
bool pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
|
bool pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ DEPS=../pb_decode.h ../pb_encode.h ../pb.h person.pb.h callbacks.pb.h unittests.
|
|||||||
TESTS=test_decode1 test_encode1 decode_unittests encode_unittests test_no_messages
|
TESTS=test_decode1 test_encode1 decode_unittests encode_unittests test_no_messages
|
||||||
|
|
||||||
# More strict checks for the core part of nanopb
|
# More strict checks for the core part of nanopb
|
||||||
CFLAGS_CORE=-pedantic -Wextra -Wcast-qual -Wlogical-op
|
CFLAGS_CORE=-pedantic -Wextra -Wcast-qual -Wlogical-op -Wconversion
|
||||||
|
|
||||||
all: breakpoints $(TESTS) run_unittests
|
all: breakpoints $(TESTS) run_unittests
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ coverage: run_unittests
|
|||||||
gcov pb_encode.gcda
|
gcov pb_encode.gcda
|
||||||
gcov pb_decode.gcda
|
gcov pb_decode.gcda
|
||||||
|
|
||||||
run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 test_encode2 test_encode3 test_decode1 test_decode2 test_decode3 test_encode_callbacks test_decode_callbacks test_missing_fields
|
run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 test_encode2 test_encode3 test_decode1 test_decode2 test_decode3 test_encode_callbacks test_decode_callbacks test_missing_fields test_options
|
||||||
rm -f *.gcda
|
rm -f *.gcda
|
||||||
|
|
||||||
./decode_unittests > /dev/null
|
./decode_unittests > /dev/null
|
||||||
@@ -70,6 +70,9 @@ run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 te
|
|||||||
[ "`./test_encode2 | ./test_decode2`" = \
|
[ "`./test_encode2 | ./test_decode2`" = \
|
||||||
"`./test_encode2 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ]
|
"`./test_encode2 | protoc --decode=Person -I. -I../generator -I/usr/include person.proto`" ]
|
||||||
|
|
||||||
|
[ "`./test_decode2 < person_with_extra_field.pb`" = \
|
||||||
|
"`./test_encode2 | ./test_decode2`" ]
|
||||||
|
|
||||||
[ "`./test_encode_callbacks | ./test_decode_callbacks`" = \
|
[ "`./test_encode_callbacks | ./test_decode_callbacks`" = \
|
||||||
"`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ]
|
"`./test_encode_callbacks | protoc --decode=TestMessage callbacks.proto`" ]
|
||||||
|
|
||||||
@@ -79,5 +82,13 @@ run_unittests: decode_unittests encode_unittests test_cxxcompile test_encode1 te
|
|||||||
|
|
||||||
./test_missing_fields
|
./test_missing_fields
|
||||||
|
|
||||||
|
test_options: options.pb.h options.expected
|
||||||
|
cat options.expected | while read -r p; do \
|
||||||
|
if ! grep -q "$$p" $<; then \
|
||||||
|
echo Expected: "$$p"; \
|
||||||
|
exit 1; \
|
||||||
|
fi \
|
||||||
|
done
|
||||||
|
|
||||||
run_fuzztest: test_decode2
|
run_fuzztest: test_decode2
|
||||||
bash -c 'I=1; while true; do cat /dev/urandom | ./test_decode2 > /dev/null; I=$$(($$I+1)); echo -en "\r$$I"; done'
|
bash -c 'I=1; while true; do cat /dev/urandom | ./test_decode2 > /dev/null; I=$$(($$I+1)); echo -en "\r$$I"; done'
|
||||||
|
|||||||
5
tests/options.expected
Normal file
5
tests/options.expected
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
char filesize\[20\];
|
||||||
|
char msgsize\[30\];
|
||||||
|
char fieldsize\[40\];
|
||||||
|
pb_callback_t int32_callback;
|
||||||
|
[^_]EnumValue1 = 1
|
||||||
39
tests/options.proto
Normal file
39
tests/options.proto
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* Test nanopb option parsing.
|
||||||
|
* options.expected lists the patterns that are searched for in the output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "nanopb.proto";
|
||||||
|
|
||||||
|
// File level options
|
||||||
|
option (nanopb_fileopt).max_size = 20;
|
||||||
|
|
||||||
|
message Message1
|
||||||
|
{
|
||||||
|
required string filesize = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message level options
|
||||||
|
message Message2
|
||||||
|
{
|
||||||
|
option (nanopb_msgopt).max_size = 30;
|
||||||
|
required string msgsize = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field level options
|
||||||
|
message Message3
|
||||||
|
{
|
||||||
|
required string fieldsize = 1 [(nanopb).max_size = 40];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forced callback field
|
||||||
|
message Message4
|
||||||
|
{
|
||||||
|
required int32 int32_callback = 1 [(nanopb).type = FT_CALLBACK];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short enum names
|
||||||
|
enum Enum1
|
||||||
|
{
|
||||||
|
option (nanopb_enumopt).long_names = false;
|
||||||
|
EnumValue1 = 1;
|
||||||
|
}
|
||||||
BIN
tests/person_with_extra_field.pb
Normal file
BIN
tests/person_with_extra_field.pb
Normal file
Binary file not shown.
@@ -63,6 +63,12 @@ int main()
|
|||||||
uint8_t buffer[512];
|
uint8_t buffer[512];
|
||||||
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
|
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
|
||||||
|
|
||||||
|
if (!feof(stdin))
|
||||||
|
{
|
||||||
|
printf("Message does not fit in buffer\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Construct a pb_istream_t for reading from the buffer */
|
/* Construct a pb_istream_t for reading from the buffer */
|
||||||
pb_istream_t stream = pb_istream_from_buffer(buffer, count);
|
pb_istream_t stream = pb_istream_from_buffer(buffer, count);
|
||||||
|
|
||||||
|
|||||||
@@ -59,13 +59,6 @@ bool callback(pb_istream_t *stream, uint8_t *buf, size_t count)
|
|||||||
FILE *file = (FILE*)stream->state;
|
FILE *file = (FILE*)stream->state;
|
||||||
bool status;
|
bool status;
|
||||||
|
|
||||||
if (buf == NULL)
|
|
||||||
{
|
|
||||||
/* Skipping data */
|
|
||||||
while (count-- && fgetc(file) != EOF);
|
|
||||||
return count == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = (fread(buf, 1, count, file) == count);
|
status = (fread(buf, 1, count, file) == count);
|
||||||
|
|
||||||
if (feof(file))
|
if (feof(file))
|
||||||
|
|||||||
@@ -26,20 +26,20 @@ bool check_alltypes(pb_istream_t *stream, int mode)
|
|||||||
if (!pb_decode(stream, AllTypes_fields, &alltypes))
|
if (!pb_decode(stream, AllTypes_fields, &alltypes))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TEST(alltypes.req_int32 == 1001);
|
TEST(alltypes.req_int32 == -1001);
|
||||||
TEST(alltypes.req_int64 == 1002);
|
TEST(alltypes.req_int64 == -1002);
|
||||||
TEST(alltypes.req_uint32 == 1003);
|
TEST(alltypes.req_uint32 == 1003);
|
||||||
TEST(alltypes.req_uint64 == 1004);
|
TEST(alltypes.req_uint64 == 1004);
|
||||||
TEST(alltypes.req_sint32 == 1005);
|
TEST(alltypes.req_sint32 == -1005);
|
||||||
TEST(alltypes.req_sint64 == 1006);
|
TEST(alltypes.req_sint64 == -1006);
|
||||||
TEST(alltypes.req_bool == true);
|
TEST(alltypes.req_bool == true);
|
||||||
|
|
||||||
TEST(alltypes.req_fixed32 == 1008);
|
TEST(alltypes.req_fixed32 == 1008);
|
||||||
TEST(alltypes.req_sfixed32 == 1009);
|
TEST(alltypes.req_sfixed32 == -1009);
|
||||||
TEST(alltypes.req_float == 1010.0f);
|
TEST(alltypes.req_float == 1010.0f);
|
||||||
|
|
||||||
TEST(alltypes.req_fixed64 == 1011);
|
TEST(alltypes.req_fixed64 == 1011);
|
||||||
TEST(alltypes.req_sfixed64 == 1012);
|
TEST(alltypes.req_sfixed64 == -1012);
|
||||||
TEST(alltypes.req_double == 1013.0f);
|
TEST(alltypes.req_double == 1013.0f);
|
||||||
|
|
||||||
TEST(strcmp(alltypes.req_string, "1014") == 0);
|
TEST(strcmp(alltypes.req_string, "1014") == 0);
|
||||||
@@ -50,20 +50,20 @@ bool check_alltypes(pb_istream_t *stream, int mode)
|
|||||||
TEST(alltypes.req_submsg.substuff3 == 3);
|
TEST(alltypes.req_submsg.substuff3 == 3);
|
||||||
TEST(alltypes.req_enum == MyEnum_Truth);
|
TEST(alltypes.req_enum == MyEnum_Truth);
|
||||||
|
|
||||||
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == 2001 && alltypes.rep_int32[0] == 0);
|
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0);
|
||||||
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == 2002 && alltypes.rep_int64[0] == 0);
|
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == -2002 && alltypes.rep_int64[0] == 0);
|
||||||
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
|
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
|
||||||
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
|
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
|
||||||
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == 2005 && alltypes.rep_sint32[0] == 0);
|
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0);
|
||||||
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == 2006 && alltypes.rep_sint64[0] == 0);
|
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == -2006 && alltypes.rep_sint64[0] == 0);
|
||||||
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
|
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
|
||||||
|
|
||||||
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
|
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
|
||||||
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == 2009 && alltypes.rep_sfixed32[0] == 0);
|
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0);
|
||||||
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
|
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
|
||||||
|
|
||||||
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
|
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
|
||||||
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == 2012 && alltypes.rep_sfixed64[0] == 0);
|
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == -2012 && alltypes.rep_sfixed64[0] == 0);
|
||||||
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
|
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
|
||||||
|
|
||||||
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
|
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
|
||||||
|
|||||||
@@ -14,20 +14,20 @@ int main(int argc, char **argv)
|
|||||||
/* Initialize the structure with constants */
|
/* Initialize the structure with constants */
|
||||||
AllTypes alltypes = {0};
|
AllTypes alltypes = {0};
|
||||||
|
|
||||||
alltypes.req_int32 = 1001;
|
alltypes.req_int32 = -1001;
|
||||||
alltypes.req_int64 = 1002;
|
alltypes.req_int64 = -1002;
|
||||||
alltypes.req_uint32 = 1003;
|
alltypes.req_uint32 = 1003;
|
||||||
alltypes.req_uint64 = 1004;
|
alltypes.req_uint64 = 1004;
|
||||||
alltypes.req_sint32 = 1005;
|
alltypes.req_sint32 = -1005;
|
||||||
alltypes.req_sint64 = 1006;
|
alltypes.req_sint64 = -1006;
|
||||||
alltypes.req_bool = true;
|
alltypes.req_bool = true;
|
||||||
|
|
||||||
alltypes.req_fixed32 = 1008;
|
alltypes.req_fixed32 = 1008;
|
||||||
alltypes.req_sfixed32 = 1009;
|
alltypes.req_sfixed32 = -1009;
|
||||||
alltypes.req_float = 1010.0f;
|
alltypes.req_float = 1010.0f;
|
||||||
|
|
||||||
alltypes.req_fixed64 = 1011;
|
alltypes.req_fixed64 = 1011;
|
||||||
alltypes.req_sfixed64 = 1012;
|
alltypes.req_sfixed64 = -1012;
|
||||||
alltypes.req_double = 1013.0;
|
alltypes.req_double = 1013.0;
|
||||||
|
|
||||||
strcpy(alltypes.req_string, "1014");
|
strcpy(alltypes.req_string, "1014");
|
||||||
@@ -37,20 +37,20 @@ int main(int argc, char **argv)
|
|||||||
alltypes.req_submsg.substuff2 = 1016;
|
alltypes.req_submsg.substuff2 = 1016;
|
||||||
alltypes.req_enum = MyEnum_Truth;
|
alltypes.req_enum = MyEnum_Truth;
|
||||||
|
|
||||||
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = 2001;
|
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001;
|
||||||
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = 2002;
|
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = -2002;
|
||||||
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
|
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
|
||||||
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
|
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
|
||||||
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = 2005;
|
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005;
|
||||||
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = 2006;
|
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = -2006;
|
||||||
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
|
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
|
||||||
|
|
||||||
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008;
|
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008;
|
||||||
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = 2009;
|
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = -2009;
|
||||||
alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f;
|
alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f;
|
||||||
|
|
||||||
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011;
|
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011;
|
||||||
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = 2012;
|
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = -2012;
|
||||||
alltypes.rep_double_count = 5; alltypes.rep_double[4] = 2013.0;
|
alltypes.rep_double_count = 5; alltypes.rep_double[4] = 2013.0;
|
||||||
|
|
||||||
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");
|
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");
|
||||||
|
|||||||
10
tools/set_version.sh
Executable file
10
tools/set_version.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Run this from the top directory of nanopb tree.
|
||||||
|
# e.g. user@localhost:~/nanopb$ tools/set_version.sh nanopb-0.1.9-dev
|
||||||
|
# It sets the version number in pb.h and generator/nanopb_generator.py.
|
||||||
|
|
||||||
|
sed -i -e 's/nanopb_version\s*=\s*"[^"]*"/nanopb_version = "'$1'"/' generator/nanopb_generator.py
|
||||||
|
sed -i -e 's/#define\s*NANOPB_VERSION\s*.*/#define NANOPB_VERSION '$1'/' pb.h
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user