Unverified Commit 1b6519e4 authored by Robert Edmonds's avatar Robert Edmonds Committed by GitHub

Merge pull request #466 from protobuf-c/options

protoc-c: add custom options support
parents 53004955 5ae0762b
......@@ -42,7 +42,8 @@ lib_LTLIBRARIES += \
protobuf-c/libprotobuf-c.la
nobase_include_HEADERS += \
protobuf-c/protobuf-c.h
protobuf-c/protobuf-c.h \
protobuf-c/protobuf-c.proto
protobuf_c_libprotobuf_c_la_SOURCES = \
protobuf-c/protobuf-c.c \
......@@ -99,6 +100,8 @@ protoc_c_protoc_gen_c_SOURCES = \
protoc-c/c_service.h \
protoc-c/c_string_field.cc \
protoc-c/c_string_field.h \
protobuf-c/protobuf-c.pb.cc \
protobuf-c/protobuf-c.pb.h \
protoc-c/main.cc
protoc_c_protoc_gen_c_CXXFLAGS = \
$(AM_CXXFLAGS) \
......@@ -107,6 +110,12 @@ protoc_c_protoc_gen_c_LDADD = \
$(protobuf_LIBS) \
-lprotoc
protobuf-c/protobuf-c.pb.cc protobuf-c/protobuf-c.pb.h: @PROTOC@ $(top_srcdir)/protobuf-c/protobuf-c.proto
$(AM_V_GEN)@PROTOC@ -I$(top_srcdir) --cpp_out=$(top_builddir) $(top_srcdir)/protobuf-c/protobuf-c.proto
BUILT_SOURCES += \
protobuf-c/protobuf-c.pb.cc \
protobuf-c/protobuf-c.pb.h
#
# protoc-c compat link
#
......@@ -155,7 +164,8 @@ noinst_PROGRAMS += \
t_generated_code2_cxx_generate_packed_data_SOURCES = \
t/generated-code2/cxx-generate-packed-data.cc \
t/test-full.pb.cc
t/test-full.pb.cc \
protobuf-c/protobuf-c.pb.cc
$(t_generated_code2_cxx_generate_packed_data_OBJECTS): t/test-full.pb.h
t_generated_code2_cxx_generate_packed_data_CXXFLAGS = \
$(AM_CXXFLAGS) \
......@@ -216,6 +226,23 @@ t_version_version_SOURCES = \
t_version_version_LDADD = \
protobuf-c/libprotobuf-c.la
# Issue #204
check_PROGRAMS += \
t/issue204/issue204
TESTS += \
t/issue204/issue204
t_issue204_issue204_SOURCES = \
t/issue204/issue204.c \
t/issue204/issue204.pb-c.c
t_issue204_issue204_LDADD = \
protobuf-c/libprotobuf-c.la
t/issue204/issue204.pb-c.c t/issue204/issue204.pb-c.h: $(top_builddir)/protoc-c/protoc-gen-c$(EXEEXT) $(top_srcdir)/t/issue204/issue204.proto
$(AM_V_GEN)@PROTOC@ --plugin=protoc-gen-c=$(top_builddir)/protoc-c/protoc-gen-c$(EXEEXT) -I$(top_srcdir) --c_out=$(top_builddir) $(top_srcdir)/t/issue204/issue204.proto
BUILT_SOURCES += \
t/issue204/issue204.pb-c.c t/issue204/issue204.pb-c.h
EXTRA_DIST += \
t/issue204/issue204.proto
# Issue #220
check_PROGRAMS += \
t/issue220/issue220
......
......@@ -91,8 +91,11 @@ IF(BUILD_PROTOC)
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)
ADD_CUSTOM_COMMAND(OUTPUT protobuf-c/protobuf-c.pb.cc protobuf-c/protobuf-c.pb.h
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out ${CMAKE_BINARY_DIR} -I${MAIN_DIR} ${MAIN_DIR}/protobuf-c/protobuf-c.proto)
FILE(GLOB PROTOC_GEN_C_SRC ${MAIN_DIR}/protoc-c/*.h ${MAIN_DIR}/protoc-c/*.cc )
ADD_EXECUTABLE(protoc-gen-c ${PROTOC_GEN_C_SRC})
ADD_EXECUTABLE(protoc-gen-c ${PROTOC_GEN_C_SRC} protobuf-c/protobuf-c.pb.cc protobuf-c/protobuf-c.pb.h)
TARGET_LINK_LIBRARIES(protoc-gen-c ${PROTOBUF_PROTOC_LIBRARY} ${PROTOBUF_LIBRARY})
......@@ -132,7 +135,7 @@ ADD_CUSTOM_COMMAND(OUTPUT t/test-full.pb.cc t/test-full.pb.h
GENERATE_TEST_SOURCES(${TEST_DIR}/test-full.proto t/test-full.pb-c.c t/test-full.pb-c.h)
ADD_EXECUTABLE(cxx-generate-packed-data ${TEST_DIR}/generated-code2/cxx-generate-packed-data.cc t/test-full.pb.h t/test-full.pb.cc)
ADD_EXECUTABLE(cxx-generate-packed-data ${TEST_DIR}/generated-code2/cxx-generate-packed-data.cc t/test-full.pb.h t/test-full.pb.cc protobuf-c/protobuf-c.pb.cc protobuf-c/protobuf-c.pb.h)
TARGET_LINK_LIBRARIES(cxx-generate-packed-data ${PROTOBUF_LIBRARY})
IF (MSVC AND BUILD_SHARED_LIBS)
TARGET_COMPILE_DEFINITIONS(cxx-generate-packed-data PRIVATE -DPROTOBUF_USE_DLLS)
......@@ -182,7 +185,7 @@ INSTALL(TARGETS protoc-gen-c RUNTIME DESTINATION bin)
ENDIF() # BUILD_PROTOC
INSTALL(TARGETS protobuf-c LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin)
INSTALL(FILES ${MAIN_DIR}/protobuf-c/protobuf-c.h DESTINATION include/protobuf-c)
INSTALL(FILES ${MAIN_DIR}/protobuf-c/protobuf-c.h ${MAIN_DIR}/protobuf-c/protobuf-c.proto DESTINATION include/protobuf-c)
INSTALL(FILES ${MAIN_DIR}/protobuf-c/protobuf-c.h DESTINATION include)
INSTALL(FILES ${CMAKE_BINARY_DIR}/protobuf-c.pdb DESTINATION lib OPTIONAL)
......
/*
* Copyright (c) 2021, the protobuf-c authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
syntax = "proto2";
import "google/protobuf/descriptor.proto";
// We never need to generate protobuf-c.pb-c.{c,h}, the options are used
// only by protoc-gen-c, never by the protobuf-c runtime itself
option (pb_c_file).no_generate = true;
message ProtobufCFileOptions {
// Suppresses pb-c.{c,h} file output completely.
optional bool no_generate = 1 [default = false];
// Generate helper pack/unpack functions?
// For backwards compatibility, if this field is not explicitly set,
// only top-level message pack/unpack functions will be generated
optional bool gen_pack_helpers = 2 [default = true];
// Generate helper init message functions?
optional bool gen_init_helpers = 3 [default = true];
// Use const char * instead of char * for string fields
optional bool const_strings = 4 [default = false];
// For oneof fields, set ProtobufCFieldDescriptor name field to the
// name of the containing oneof, instead of the field name
optional bool use_oneof_field_name = 5 [default = false];
// Overrides the package name, if present
optional string c_package = 6;
}
extend google.protobuf.FileOptions {
optional ProtobufCFileOptions pb_c_file = 1019;
}
message ProtobufCMessageOptions {
// Overrides the parent setting only if present
optional bool gen_pack_helpers = 1 [default = false];
// Overrides the parent setting only if present
optional bool gen_init_helpers = 2 [default = true];
// Reserved base message field name
optional string base_field_name = 3 [default = "base"];
}
extend google.protobuf.MessageOptions {
optional ProtobufCMessageOptions pb_c_msg = 1019;
}
message ProtobufCFieldOptions {
// Treat string as bytes in generated code
optional bool string_as_bytes = 1 [default = false];
}
extend google.protobuf.FieldOptions {
optional ProtobufCFieldOptions pb_c_field = 1019;
}
......@@ -64,7 +64,7 @@
#include <protoc-c/c_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/descriptor.pb.h>
#include <protobuf-c/protobuf-c.pb.h>
namespace google {
namespace protobuf {
......@@ -114,7 +114,7 @@ void BytesFieldGenerator::GenerateStructMembers(io::Printer* printer) const
void BytesFieldGenerator::GenerateDefaultValueDeclarations(io::Printer* printer) const
{
std::map<std::string, std::string> vars;
vars["default_value_data"] = FullNameToLower(descriptor_->full_name())
vars["default_value_data"] = FullNameToLower(descriptor_->full_name(), descriptor_->file())
+ "__default_value_data";
printer->Print(vars, "extern uint8_t $default_value_data$[];\n");
}
......@@ -122,7 +122,7 @@ void BytesFieldGenerator::GenerateDefaultValueDeclarations(io::Printer* printer)
void BytesFieldGenerator::GenerateDefaultValueImplementations(io::Printer* printer) const
{
std::map<std::string, std::string> vars;
vars["default_value_data"] = FullNameToLower(descriptor_->full_name())
vars["default_value_data"] = FullNameToLower(descriptor_->full_name(), descriptor_->file())
+ "__default_value_data";
vars["escaped"] = CEscape(descriptor_->default_value_string());
printer->Print(vars, "uint8_t $default_value_data$[] = \"$escaped$\";\n");
......@@ -132,7 +132,7 @@ std::string BytesFieldGenerator::GetDefaultValue(void) const
return "{ "
+ SimpleItoa(descriptor_->default_value_string().size())
+ ", "
+ FullNameToLower(descriptor_->full_name())
+ FullNameToLower(descriptor_->full_name(), descriptor_->file())
+ "__default_value_data }";
}
void BytesFieldGenerator::GenerateStaticInit(io::Printer* printer) const
......
......@@ -82,9 +82,9 @@ EnumGenerator::~EnumGenerator() {}
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
std::map<std::string, std::string> vars;
vars["classname"] = FullNameToC(descriptor_->full_name());
vars["classname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
vars["shortname"] = descriptor_->name();
vars["uc_name"] = FullNameToUpper(descriptor_->full_name());
vars["uc_name"] = FullNameToUpper(descriptor_->full_name(), descriptor_->file());
SourceLocation sourceLoc;
descriptor_->GetSourceLocation(&sourceLoc);
......@@ -98,7 +98,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
vars["opt_comma"] = ",";
vars["prefix"] = FullNameToUpper(descriptor_->full_name()) + "__";
vars["prefix"] = FullNameToUpper(descriptor_->full_name(), descriptor_->file()) + "__";
for (int i = 0; i < descriptor_->value_count(); i++) {
vars["name"] = descriptor_->value(i)->name();
vars["number"] = SimpleItoa(descriptor_->value(i)->number());
......@@ -132,8 +132,8 @@ void EnumGenerator::GenerateDescriptorDeclarations(io::Printer* printer) {
} else {
vars["dllexport"] = dllexport_decl_ + " ";
}
vars["classname"] = FullNameToC(descriptor_->full_name());
vars["lcclassname"] = FullNameToLower(descriptor_->full_name());
vars["classname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
vars["lcclassname"] = FullNameToLower(descriptor_->full_name(), descriptor_->file());
printer->Print(vars,
"extern $dllexport$const ProtobufCEnumDescriptor $lcclassname$__descriptor;\n");
......@@ -154,7 +154,7 @@ void EnumGenerator::GenerateValueInitializer(io::Printer *printer, int index)
descriptor_->file()->options().optimize_for() ==
FileOptions_OptimizeMode_CODE_SIZE;
vars["enum_value_name"] = vd->name();
vars["c_enum_value_name"] = FullNameToUpper(descriptor_->full_name()) + "__" + vd->name();
vars["c_enum_value_name"] = FullNameToUpper(descriptor_->full_name(), descriptor_->file()) + "__" + vd->name();
vars["value"] = SimpleItoa(vd->number());
if (optimize_code_size)
printer->Print(vars, " { NULL, NULL, $value$ }, /* CODE_SIZE */\n");
......@@ -184,8 +184,8 @@ static int compare_value_indices_by_name(const void *a, const void *b)
void EnumGenerator::GenerateEnumDescriptor(io::Printer* printer) {
std::map<std::string, std::string> vars;
vars["fullname"] = descriptor_->full_name();
vars["lcclassname"] = FullNameToLower(descriptor_->full_name());
vars["cname"] = FullNameToC(descriptor_->full_name());
vars["lcclassname"] = FullNameToLower(descriptor_->full_name(), descriptor_->file());
vars["cname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
vars["shortname"] = descriptor_->name();
vars["packagename"] = descriptor_->file()->package();
vars["value_count"] = SimpleItoa(descriptor_->value_count());
......
......@@ -78,9 +78,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables) {
(*variables)["name"] = FieldName(descriptor);
(*variables)["type"] = FullNameToC(descriptor->enum_type()->full_name());
(*variables)["type"] = FullNameToC(descriptor->enum_type()->full_name(), descriptor->enum_type()->file());
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
(*variables)["default"] = FullNameToUpper(default_value->type()->full_name())
(*variables)["default"] = FullNameToUpper(default_value->type()->full_name(), default_value->type()->file())
+ "__" + default_value->name();
(*variables)["deprecated"] = FieldDeprecated(descriptor);
}
......@@ -138,7 +138,7 @@ void EnumFieldGenerator::GenerateStaticInit(io::Printer* printer) const
void EnumFieldGenerator::GenerateDescriptorInitializer(io::Printer* printer) const
{
std::string addr = "&" + FullNameToLower(descriptor_->enum_type()->full_name()) + "__descriptor";
std::string addr = "&" + FullNameToLower(descriptor_->enum_type()->full_name(), descriptor_->enum_type()->file()) + "__descriptor";
GenerateDescriptorInitializerGeneric(printer, true, "ENUM", addr);
}
......
......@@ -67,7 +67,7 @@
#include <protoc-c/c_enum_field.h>
#include <protoc-c/c_message_field.h>
#include <protoc-c/c_helpers.h>
#include <google/protobuf/descriptor.pb.h>
#include <protobuf-c/protobuf-c.pb.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/printer.h>
......@@ -107,15 +107,19 @@ void FieldGenerator::GenerateDescriptorInitializerGeneric(io::Printer* printer,
const std::string &descriptor_addr) const
{
std::map<std::string, std::string> variables;
const OneofDescriptor *oneof = descriptor_->containing_oneof();
const ProtobufCFileOptions opt = descriptor_->file()->options().GetExtension(pb_c_file);
variables["TYPE"] = type_macro;
variables["classname"] = FullNameToC(FieldScope(descriptor_)->full_name());
variables["classname"] = FullNameToC(FieldScope(descriptor_)->full_name(), FieldScope(descriptor_)->file());
variables["name"] = FieldName(descriptor_);
if (opt.use_oneof_field_name())
variables["proto_name"] = oneof->name();
else
variables["proto_name"] = descriptor_->name();
variables["descriptor_addr"] = descriptor_addr;
variables["value"] = SimpleItoa(descriptor_->number());
const OneofDescriptor *oneof = descriptor_->containing_oneof();
if (oneof != NULL)
variables["oneofname"] = FullNameToLower(oneof->name());
variables["oneofname"] = CamelToLower(oneof->name());
if (FieldSyntax(descriptor_) == 3 &&
descriptor_->label() == FieldDescriptor::LABEL_OPTIONAL) {
......@@ -127,7 +131,7 @@ void FieldGenerator::GenerateDescriptorInitializerGeneric(io::Printer* printer,
if (descriptor_->has_default_value()) {
variables["default_value"] = std::string("&")
+ FullNameToLower(descriptor_->full_name())
+ FullNameToLower(descriptor_->full_name(), descriptor_->file())
+ "__default_value";
} else if (FieldSyntax(descriptor_) == 3 &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
......@@ -203,10 +207,14 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
}
FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
const ProtobufCFieldOptions opt = field->options().GetExtension(pb_c_field);
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
return new MessageFieldGenerator(field);
case FieldDescriptor::TYPE_STRING:
if (opt.string_as_bytes())
return new BytesFieldGenerator(field);
else
return new StringFieldGenerator(field);
case FieldDescriptor::TYPE_BYTES:
return new BytesFieldGenerator(field);
......
......@@ -68,7 +68,7 @@
#include <protoc-c/c_helpers.h>
#include <protoc-c/c_message.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>
#include <protobuf-c/protobuf-c.pb.h>
#include "protobuf-c.h"
......@@ -110,8 +110,6 @@ FileGenerator::FileGenerator(const FileDescriptor* file,
extension_generators_[i].reset(
new ExtensionGenerator(file->extension(i), dllexport_decl));
}
SplitStringUsing(file_->package(), ".", &package_parts_);
}
FileGenerator::~FileGenerator() {}
......@@ -157,10 +155,14 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"protoc_version", SimpleItoa(PROTOBUF_C_VERSION_NUMBER));
for (int i = 0; i < file_->dependency_count(); i++) {
const ProtobufCFileOptions opt =
file_->dependency(i)->options().GetExtension(pb_c_file);
if (!opt.no_generate()) {
printer->Print(
"#include \"$dependency$.pb-c.h\"\n",
"dependency", StripProto(file_->dependency(i)->name()));
}
}
printer->Print("\n");
......@@ -187,7 +189,13 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
}
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateHelperFunctionDeclarations(printer, false);
const ProtobufCFileOptions opt = file_->options().GetExtension(pb_c_file);
message_generators_[i]->GenerateHelperFunctionDeclarations(
printer,
opt.has_gen_pack_helpers(),
opt.gen_pack_helpers(),
opt.gen_init_helpers());
}
printer->Print("/* --- per-message closures --- */\n\n");
......@@ -238,34 +246,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"filename", file_->name(),
"basename", StripProto(file_->name()));
#if 0
// For each dependency, write a prototype for that dependency's
// BuildDescriptors() function. We don't expose these in the header because
// they are internal implementation details, and since this is generated code
// we don't have the usual risks involved with declaring external functions
// within a .cc file.
for (int i = 0; i < file_->dependency_count(); i++) {
const FileDescriptor* dependency = file_->dependency(i);
// Open the dependency's namespace.
vector<string> dependency_package_parts;
SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
// Declare its BuildDescriptors() function.
printer->Print(
"void $function$();",
"function", GlobalBuildDescriptorsName(dependency->name()));
// Close the namespace.
for (int i = 0; i < dependency_package_parts.size(); i++) {
printer->Print(" }");
}
printer->Print("\n");
}
#endif
const ProtobufCFileOptions opt = file_->options().GetExtension(pb_c_file);
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateHelperFunctionDefinitions(printer, false);
message_generators_[i]->GenerateHelperFunctionDefinitions(
printer,
opt.has_gen_pack_helpers(),
opt.gen_pack_helpers(),
opt.gen_init_helpers());
}
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateMessageDescriptor(printer);
message_generators_[i]->GenerateMessageDescriptor(printer,
opt.gen_init_helpers());
}
for (int i = 0; i < file_->enum_type_count(); i++) {
enum_generators_[i]->GenerateEnumDescriptor(printer);
......
......@@ -104,9 +104,6 @@ class FileGenerator {
std::unique_ptr<std::unique_ptr<ServiceGenerator>[]> service_generators_;
std::unique_ptr<std::unique_ptr<ExtensionGenerator>[]> extension_generators_;
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
std::vector<std::string> package_parts_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};
......
......@@ -70,7 +70,7 @@
#include <protoc-c/c_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.pb.h>
#include <protobuf-c/protobuf-c.pb.h>
namespace google {
namespace protobuf {
......@@ -106,6 +106,9 @@ bool CGenerator::Generate(const FileDescriptor* file,
const std::string& parameter,
OutputDirectory* output_directory,
std::string* error) const {
if (file->options().GetExtension(pb_c_file).no_generate())
return true;
std::vector<std::pair<std::string, std::string> > options;
ParseOptions(parameter, &options);
......
......@@ -177,9 +177,23 @@ std::string ToCamel(const std::string &name) {
return rv;
}
std::string FullNameToLower(const std::string &full_name) {
std::string OverrideFullName(const std::string &full_name,
const FileDescriptor *file) {
const ProtobufCFileOptions opt = file->options().GetExtension(pb_c_file);
if (!opt.has_c_package())
return full_name;
std::string new_name = opt.c_package();
if (file->package().empty())
new_name += ".";
return new_name + full_name.substr(file->package().length());
}
std::string FullNameToLower(const std::string &full_name,
const FileDescriptor *file) {
std::vector<std::string> pieces;
SplitStringUsing(full_name, ".", &pieces);
SplitStringUsing(OverrideFullName(full_name, file), ".", &pieces);
std::string rv = "";
for (unsigned i = 0; i < pieces.size(); i++) {
if (pieces[i] == "") continue;
......@@ -188,9 +202,10 @@ std::string FullNameToLower(const std::string &full_name) {
}
return rv;
}
std::string FullNameToUpper(const std::string &full_name) {
std::string FullNameToUpper(const std::string &full_name,
const FileDescriptor *file) {
std::vector<std::string> pieces;
SplitStringUsing(full_name, ".", &pieces);
SplitStringUsing(OverrideFullName(full_name, file), ".", &pieces);
std::string rv = "";
for (unsigned i = 0; i < pieces.size(); i++) {
if (pieces[i] == "") continue;
......@@ -199,9 +214,10 @@ std::string FullNameToUpper(const std::string &full_name) {
}
return rv;
}
std::string FullNameToC(const std::string &full_name) {
std::string FullNameToC(const std::string &full_name,
const FileDescriptor *file) {
std::vector<std::string> pieces;
SplitStringUsing(full_name, ".", &pieces);
SplitStringUsing(OverrideFullName(full_name, file), ".", &pieces);
std::string rv = "";
for (unsigned i = 0; i < pieces.size(); i++) {
if (pieces[i] == "") continue;
......@@ -278,37 +294,6 @@ std::set<std::string> MakeKeywordsMap() {
std::set<std::string> kKeywords = MakeKeywordsMap();
std::string ClassName(const Descriptor* descriptor, bool qualified) {
// Find "outer", the descriptor of the top-level message in which
// "descriptor" is embedded.
const Descriptor* outer = descriptor;
while (outer->containing_type() != NULL) outer = outer->containing_type();
const std::string& outer_name = outer->full_name();
std::string inner_name = descriptor->full_name().substr(outer_name.size());
if (qualified) {
return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
} else {
return outer->name() + DotsToUnderscores(inner_name);
}
}
std::string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
if (enum_descriptor->containing_type() == NULL) {
if (qualified) {
return DotsToColons(enum_descriptor->full_name());
} else {
return enum_descriptor->name();
}
} else {
std::string result = ClassName(enum_descriptor->containing_type(), qualified);
result += '_';
result += enum_descriptor->name();
return result;
}
}
std::string FieldName(const FieldDescriptor* field) {
std::string result = ToLower(field->name());
if (kKeywords.count(result) > 0) {
......
......@@ -67,7 +67,7 @@
#include <vector>
#include <sstream>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <protobuf-c/protobuf-c.pb.h>
#include <google/protobuf/io/printer.h>
namespace google {
......@@ -75,17 +75,6 @@ namespace protobuf {
namespace compiler {
namespace c {
// Returns the non-nested type name for the given type. If "qualified" is
// true, prefix the type with the full namespace. For example, if you had:
// package foo.bar;
// message Baz { message Qux {} }
// Then the qualified ClassName for Qux would be:
// Foo__Bar__Baz_Qux
// While the non-qualified version would be:
// Baz_Qux
std::string ClassName(const Descriptor* descriptor, bool qualified);
std::string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
// --- Borrowed from stubs. ---
template <typename T> std::string SimpleItoa(T n) {
std::stringstream stream;
......@@ -132,11 +121,11 @@ std::string ToLower(const std::string &class_name);
std::string ToUpper(const std::string &class_name);
// full_name() to lowercase with underscores
std::string FullNameToLower(const std::string &full_name);
std::string FullNameToUpper(const std::string &full_name);
std::string FullNameToLower(const std::string &full_name, const FileDescriptor *file);
std::string FullNameToUpper(const std::string &full_name, const FileDescriptor *file);
// full_name() to c-typename (with underscores for packages, otherwise camel case)
std::string FullNameToC(const std::string &class_name);
std::string FullNameToC(const std::string &class_name, const FileDescriptor *file);
// Splits, indents, formats, and prints comment lines
void PrintComment (io::Printer* printer, std::string comment);
......
This diff is collapsed.
......@@ -111,14 +111,20 @@ class MessageGenerator {
void GenerateStructStaticInitMacro(io::Printer* printer);
// Generate standard helper functions declarations for this message.
void GenerateHelperFunctionDeclarations(io::Printer* printer, bool is_submessage);
void GenerateHelperFunctionDeclarations(io::Printer* printer,
bool is_pack_deep,
bool gen_pack,
bool gen_init);
// Source file stuff.
// Generate code that initializes the global variable storing the message's
// descriptor.
void GenerateMessageDescriptor(io::Printer* printer);
void GenerateHelperFunctionDefinitions(io::Printer* printer, bool is_submessage);
void GenerateMessageDescriptor(io::Printer* printer, bool gen_init);
void GenerateHelperFunctionDefinitions(io::Printer* printer,
bool is_pack_deep,
bool gen_pack,
bool gen_init);
private:
......
......@@ -85,7 +85,7 @@ void MessageFieldGenerator::GenerateStructMembers(io::Printer* printer) const
{
std::map<std::string, std::string> vars;
vars["name"] = FieldName(descriptor_);
vars["type"] = FullNameToC(descriptor_->message_type()->full_name());
vars["type"] = FullNameToC(descriptor_->message_type()->full_name(), descriptor_->message_type()->file());
vars["deprecated"] = FieldDeprecated(descriptor_);
switch (descriptor_->label()) {
case FieldDescriptor::LABEL_REQUIRED:
......@@ -119,7 +119,7 @@ void MessageFieldGenerator::GenerateStaticInit(io::Printer* printer) const
}
void MessageFieldGenerator::GenerateDescriptorInitializer(io::Printer* printer) const
{
std::string addr = "&" + FullNameToLower(descriptor_->message_type()->full_name()) + "__descriptor";
std::string addr = "&" + FullNameToLower(descriptor_->message_type()->full_name(), descriptor_->message_type()->file()) + "__descriptor";
GenerateDescriptorInitializerGeneric(printer, false, "MESSAGE", addr);
}
......
......@@ -74,9 +74,9 @@ ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
: descriptor_(descriptor) {
vars_["name"] = descriptor_->name();
vars_["fullname"] = descriptor_->full_name();
vars_["cname"] = FullNameToC(descriptor_->full_name());
vars_["lcfullname"] = FullNameToLower(descriptor_->full_name());
vars_["ucfullname"] = FullNameToUpper(descriptor_->full_name());
vars_["cname"] = FullNameToC(descriptor_->full_name(), descriptor_->file());
vars_["lcfullname"] = FullNameToLower(descriptor_->full_name(), descriptor_->file());
vars_["ucfullname"] = FullNameToUpper(descriptor_->full_name(), descriptor_->file());
vars_["lcfullpadd"] = ConvertToSpaces(vars_["lcfullname"]);
vars_["package"] = descriptor_->file()->package();
if (dllexport_decl.empty()) {
......@@ -107,8 +107,8 @@ void ServiceGenerator::GenerateVfuncs(io::Printer* printer)
std::string lcname = CamelToLower(method->name());
vars_["method"] = lcname;
vars_["metpad"] = ConvertToSpaces(lcname);
vars_["input_typename"] = FullNameToC(method->input_type()->full_name());
vars_["output_typename"] = FullNameToC(method->output_type()->full_name());
vars_["input_typename"] = FullNameToC(method->input_type()->full_name(), method->input_type()->file());
vars_["output_typename"] = FullNameToC(method->output_type()->full_name(), method->output_type()->file());
printer->Print(vars_,
" void (*$method$)($cname$_Service *service,\n"
" $metpad$ const $input_typename$ *input,\n"
......@@ -145,11 +145,11 @@ void ServiceGenerator::GenerateCallersDeclarations(io::Printer* printer)
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor *method = descriptor_->method(i);
std::string lcname = CamelToLower(method->name());
std::string lcfullname = FullNameToLower(descriptor_->full_name());
std::string lcfullname = FullNameToLower(descriptor_->full_name(), descriptor_->file());
vars_["method"] = lcname;
vars_["metpad"] = ConvertToSpaces(lcname);
vars_["input_typename"] = FullNameToC(method->input_type()->full_name());
vars_["output_typename"] = FullNameToC(method->output_type()->full_name());
vars_["input_typename"] = FullNameToC(method->input_type()->full_name(), method->input_type()->file());
vars_["output_typename"] = FullNameToC(method->output_type()->full_name(), method->output_type()->file());
vars_["padddddddddddddddddd"] = ConvertToSpaces(lcfullname + "__" + lcname);
printer->Print(vars_,
"void $lcfullname$__$method$(ProtobufCService *service,\n"
......@@ -208,8 +208,8 @@ void ServiceGenerator::GenerateServiceDescriptor(io::Printer* printer)
for (int i = 0; i < n_methods; i++) {
const MethodDescriptor *method = descriptor_->method(i);
vars_["method"] = method->name();
vars_["input_descriptor"] = "&" + FullNameToLower(method->input_type()->full_name()) + "__descriptor";
vars_["output_descriptor"] = "&" + FullNameToLower(method->output_type()->full_name()) + "__descriptor";
vars_["input_descriptor"] = "&" + FullNameToLower(method->input_type()->full_name(), method->input_type()->file()) + "__descriptor";
vars_["output_descriptor"] = "&" + FullNameToLower(method->output_type()->full_name(), method->output_type()->file()) + "__descriptor";
if (optimize_code_size) {
printer->Print(vars_,
" { NULL, $input_descriptor$, $output_descriptor$ }, /* CODE_SIZE */\n");
......@@ -267,11 +267,11 @@ void ServiceGenerator::GenerateCallersImplementations(io::Printer* printer)
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor *method = descriptor_->method(i);
std::string lcname = CamelToLower(method->name());
std::string lcfullname = FullNameToLower(descriptor_->full_name());
std::string lcfullname = FullNameToLower(descriptor_->full_name(), descriptor_->file());
vars_["method"] = lcname;
vars_["metpad"] = ConvertToSpaces(lcname);
vars_["input_typename"] = FullNameToC(method->input_type()->full_name());
vars_["output_typename"] = FullNameToC(method->output_type()->full_name());
vars_["input_typename"] = FullNameToC(method->input_type()->full_name(), method->input_type()->file());
vars_["output_typename"] = FullNameToC(method->output_type()->full_name(), method->output_type()->file());
vars_["padddddddddddddddddd"] = ConvertToSpaces(lcfullname + "__" + lcname);
vars_["index"] = SimpleItoa(i);
......
......@@ -64,7 +64,7 @@
#include <protoc-c/c_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/descriptor.pb.h>
#include <protobuf-c/protobuf-c.pb.h>
namespace google {
namespace protobuf {
......@@ -76,7 +76,7 @@ using internal::WireFormat;
void SetStringVariables(const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables) {
(*variables)["name"] = FieldName(descriptor);
(*variables)["default"] = FullNameToLower(descriptor->full_name())
(*variables)["default"] = FullNameToLower(descriptor->full_name(), descriptor->file())
+ "__default_value";
(*variables)["deprecated"] = FieldDeprecated(descriptor);
}
......@@ -93,13 +93,19 @@ StringFieldGenerator::~StringFieldGenerator() {}
void StringFieldGenerator::GenerateStructMembers(io::Printer* printer) const
{
const ProtobufCFileOptions opt = descriptor_->file()->options().GetExtension(pb_c_file);
switch (descriptor_->label()) {
case FieldDescriptor::LABEL_REQUIRED:
case FieldDescriptor::LABEL_OPTIONAL:
if (opt.const_strings())
printer->Print(variables_, "const ");
printer->Print(variables_, "char *$name$$deprecated$;\n");
break;
case FieldDescriptor::LABEL_REPEATED:
printer->Print(variables_, "size_t n_$name$$deprecated$;\n");
if (opt.const_strings())
printer->Print(variables_, "const ");
printer->Print(variables_, "char **$name$$deprecated$;\n");
break;
}
......@@ -123,10 +129,13 @@ std::string StringFieldGenerator::GetDefaultValue(void) const
void StringFieldGenerator::GenerateStaticInit(io::Printer* printer) const
{
std::map<std::string, std::string> vars;
const ProtobufCFileOptions opt = descriptor_->file()->options().GetExtension(pb_c_file);
if (descriptor_->has_default_value()) {
vars["default"] = GetDefaultValue();
} else if (FieldSyntax(descriptor_) == 2) {
vars["default"] = "NULL";
} else if (opt.const_strings()) {
vars["default"] = "(const char *)protobuf_c_empty_string";
} else {
vars["default"] = "(char *)protobuf_c_empty_string";
}
......
......@@ -56,7 +56,7 @@ TEST_ENUM_TYPE_NAME enum_random[] = {
T(0), T(2097152), T(268435455), T(127), T(16383), T(16384) };
#undef T
char *repeated_strings_0[] = { (char*)"onestring" };
char *repeated_strings_1[] = { (char*)"two", (char*)"string" };
char *repeated_strings_2[] = { (char*)"many", (char*)"tiny", (char*)"little", (char*)"strings", (char*)"should", (char*)"be", (char*)"handled" };
char *repeated_strings_3[] = { (char*)"one very long strings XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" };
const char *repeated_strings_0[] = { "onestring" };
const char *repeated_strings_1[] = { "two", "string" };
const char *repeated_strings_2[] = { "many", "tiny", "little", "strings", "should", "be", "handled" };
const char *repeated_strings_3[] = { "one very long strings XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" };
......@@ -432,6 +432,39 @@ static void test_required_SubMess (void)
#undef DO_TEST
}
static size_t foo__test_mess_optional__get_packed_size
(const Foo__TestMessOptional *message)
{
assert(message->base.descriptor == &foo__test_mess_optional__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
static size_t foo__test_mess_optional__pack
(const Foo__TestMessOptional *message,
uint8_t *out)
{
assert(message->base.descriptor == &foo__test_mess_optional__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
static Foo__TestMessOptional *
foo__test_mess_optional__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Foo__TestMessOptional *)
protobuf_c_message_unpack (&foo__test_mess_optional__descriptor,
allocator, len, data);
}
static void foo__test_mess_optional__free_unpacked
(Foo__TestMessOptional *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &foo__test_mess_optional__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
/* === Optional type fields === */
static void test_empty_optional (void)
{
......@@ -1241,7 +1274,7 @@ static void test_repeated_string (void)
{
#define DO_TEST(static_array, example_packed_data) \
DO_TEST_REPEATED(test_string, (char **), \
DO_TEST_REPEATED(test_string, (const char **), \
static_array, example_packed_data, \
STRING_EQUALS)
......@@ -2076,8 +2109,8 @@ test_message_check(void)
Foo__TestMessageCheck__SubMessage sm = FOO__TEST_MESSAGE_CHECK__SUB_MESSAGE__INIT;
Foo__TestMessageCheck__SubMessage sm2 = FOO__TEST_MESSAGE_CHECK__SUB_MESSAGE__INIT;
Foo__TestMessageCheck m = FOO__TEST_MESSAGE_CHECK__INIT;
char *null = NULL;
char *str = "";
const char *null = NULL;
const char *str = "";
Foo__TestMessageCheck__SubMessage *sm_p;
ProtobufCBinaryData bd;
......
#include <stdlib.h>
#include "t/issue251/issue251.pb-c.h"
int main(void)
{
TwoOneofs msg = TWO_ONEOFS__INIT;
const ProtobufCFieldDescriptor *field;
unsigned off1, off2, off_name;
field = protobuf_c_message_descriptor_get_field_by_name(
msg.base.descriptor,
"first_oneof");
assert (field);
off_name = field->offset;
field = protobuf_c_message_descriptor_get_field(
msg.base.descriptor,
10);
assert (field);
off1 = field->offset;
field = protobuf_c_message_descriptor_get_field(
msg.base.descriptor,
11);
assert (field);
off2 = field->offset;
assert (off_name == off1);
assert (off1 == off2);
field = protobuf_c_message_descriptor_get_field_by_name(
msg.base.descriptor,
"second_oneof");
assert (field);
off_name = field->offset;
field = protobuf_c_message_descriptor_get_field(
msg.base.descriptor,
20);
assert (field);
off1 = field->offset;
field = protobuf_c_message_descriptor_get_field(
msg.base.descriptor,
21);
assert (field);
off2 = field->offset;
assert (off_name == off1);
assert (off1 == off2);
return EXIT_SUCCESS;
}
import "protobuf-c/protobuf-c.proto";
option (pb_c_file).use_oneof_field_name = true;
message two_oneofs {
oneof first_oneof {
bool a = 10;
bool b = 11;
}
oneof second_oneof {
bool c = 20;
bool d = 21;
}
}
package foo;
import "protobuf-c/protobuf-c.proto";
option (pb_c_file).const_strings = true;
message SubMess {
required int32 test = 4;
......@@ -11,6 +15,8 @@ message SubMess {
repeated int32 rep = 4;
optional bytes bytes1 = 2 [default = "a \0 char"];
optional string str1 = 3 [default = "hello world\n"];
optional string str2 = 5 [default = "hello\0world\n",
(pb_c_field).string_as_bytes = true];
}
optional SubSubMess sub1 = 9;
optional SubSubMess sub2 = 10;
......@@ -115,6 +121,8 @@ message TestMessPacked {
}
message TestMessOptional {
option (pb_c_msg).gen_pack_helpers = false;
option (pb_c_msg).gen_init_helpers = false;
optional int32 test_int32 = 1;
optional sint32 test_sint32 = 2;
optional sfixed32 test_sfixed32 = 3;
......
package foo;
import "protobuf-c/protobuf-c.proto";
option (pb_c_file).c_package = "foo";
message Person {
required string name = 1;
required int32 id = 2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment