2008-08-22 20:38:05 +00:00
|
|
|
// Protocol Buffers - Google's data interchange format
|
2013-11-18 20:25:34 -05:00
|
|
|
// Copyright 2008 Google Inc. All rights reserved.
|
2008-08-22 20:38:05 +00:00
|
|
|
// http://code.google.com/p/protobuf/
|
|
|
|
//
|
2013-11-18 20:25:34 -05:00
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
2008-08-22 20:38:05 +00:00
|
|
|
//
|
2013-11-18 20:25:34 -05:00
|
|
|
// * 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.
|
|
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
|
|
// contributors may be used to endorse or promote products derived from
|
|
|
|
// this software without specific prior written permission.
|
2008-08-22 20:38:05 +00:00
|
|
|
//
|
2013-11-18 20:25:34 -05:00
|
|
|
// 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.
|
2008-08-22 20:38:05 +00:00
|
|
|
|
|
|
|
// Author: kenton@google.com (Kenton Varda)
|
|
|
|
// Based on original Protocol Buffers design by
|
|
|
|
// Sanjay Ghemawat, Jeff Dean, and others.
|
|
|
|
|
2013-11-18 20:25:34 -05:00
|
|
|
// Copyright (c) 2008-2013, Dave Benson. 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.
|
|
|
|
|
2008-08-22 20:38:05 +00:00
|
|
|
// Modified to implement C code by Dave Benson.
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
#include <map>
|
|
|
|
|
2013-11-16 17:11:48 -05:00
|
|
|
#include <protoc-c/c_enum.h>
|
|
|
|
#include <protoc-c/c_helpers.h>
|
2008-08-22 20:38:05 +00:00
|
|
|
#include <google/protobuf/io/printer.h>
|
|
|
|
|
|
|
|
namespace google {
|
|
|
|
namespace protobuf {
|
|
|
|
namespace compiler {
|
|
|
|
namespace c {
|
|
|
|
|
|
|
|
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
|
|
|
|
const string& dllexport_decl)
|
|
|
|
: descriptor_(descriptor),
|
|
|
|
dllexport_decl_(dllexport_decl) {
|
|
|
|
}
|
|
|
|
|
|
|
|
EnumGenerator::~EnumGenerator() {}
|
|
|
|
|
|
|
|
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
|
|
|
|
map<string, string> vars;
|
|
|
|
vars["classname"] = FullNameToC(descriptor_->full_name());
|
|
|
|
vars["shortname"] = descriptor_->name();
|
2011-11-12 02:32:22 +00:00
|
|
|
vars["uc_name"] = FullNameToUpper(descriptor_->full_name());
|
2008-08-22 20:38:05 +00:00
|
|
|
|
2014-12-16 18:12:54 -08:00
|
|
|
SourceLocation sourceLoc;
|
|
|
|
descriptor_->GetSourceLocation(&sourceLoc);
|
|
|
|
PrintComment (printer, sourceLoc.leading_comments);
|
|
|
|
|
2008-08-22 20:38:05 +00:00
|
|
|
printer->Print(vars, "typedef enum _$classname$ {\n");
|
|
|
|
printer->Indent();
|
|
|
|
|
|
|
|
const EnumValueDescriptor* min_value = descriptor_->value(0);
|
|
|
|
const EnumValueDescriptor* max_value = descriptor_->value(0);
|
|
|
|
|
|
|
|
|
2008-08-28 06:08:40 +00:00
|
|
|
vars["opt_comma"] = ",";
|
2011-11-12 02:32:22 +00:00
|
|
|
vars["prefix"] = FullNameToUpper(descriptor_->full_name()) + "__";
|
2008-08-22 20:38:05 +00:00
|
|
|
for (int i = 0; i < descriptor_->value_count(); i++) {
|
|
|
|
vars["name"] = descriptor_->value(i)->name();
|
|
|
|
vars["number"] = SimpleItoa(descriptor_->value(i)->number());
|
2008-08-28 06:08:40 +00:00
|
|
|
if (i + 1 == descriptor_->value_count())
|
|
|
|
vars["opt_comma"] = "";
|
2008-08-22 20:38:05 +00:00
|
|
|
|
2014-12-16 18:12:54 -08:00
|
|
|
SourceLocation valSourceLoc;
|
|
|
|
descriptor_->value(i)->GetSourceLocation(&valSourceLoc);
|
|
|
|
|
|
|
|
PrintComment (printer, valSourceLoc.leading_comments);
|
|
|
|
PrintComment (printer, valSourceLoc.trailing_comments);
|
2008-08-28 06:08:40 +00:00
|
|
|
printer->Print(vars, "$prefix$$name$ = $number$$opt_comma$\n");
|
2008-08-22 20:38:05 +00:00
|
|
|
|
|
|
|
if (descriptor_->value(i)->number() < min_value->number()) {
|
|
|
|
min_value = descriptor_->value(i);
|
|
|
|
}
|
|
|
|
if (descriptor_->value(i)->number() > max_value->number()) {
|
|
|
|
max_value = descriptor_->value(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-03 17:43:21 -04:00
|
|
|
printer->Print(vars, " PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE($uc_name$)\n");
|
2008-08-22 20:38:05 +00:00
|
|
|
printer->Outdent();
|
|
|
|
printer->Print(vars, "} $classname$;\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void EnumGenerator::GenerateDescriptorDeclarations(io::Printer* printer) {
|
|
|
|
map<string, string> vars;
|
|
|
|
if (dllexport_decl_.empty()) {
|
|
|
|
vars["dllexport"] = "";
|
|
|
|
} else {
|
|
|
|
vars["dllexport"] = dllexport_decl_ + " ";
|
|
|
|
}
|
|
|
|
vars["classname"] = FullNameToC(descriptor_->full_name());
|
|
|
|
vars["lcclassname"] = FullNameToLower(descriptor_->full_name());
|
|
|
|
|
|
|
|
printer->Print(vars,
|
|
|
|
"extern $dllexport$const ProtobufCEnumDescriptor $lcclassname$__descriptor;\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ValueIndex
|
|
|
|
{
|
|
|
|
int value;
|
|
|
|
unsigned index;
|
2008-08-27 02:14:42 +00:00
|
|
|
unsigned final_index; /* index in uniqified array of values */
|
|
|
|
const char *name;
|
2008-08-22 20:38:05 +00:00
|
|
|
};
|
|
|
|
void EnumGenerator::GenerateValueInitializer(io::Printer *printer, int index)
|
|
|
|
{
|
|
|
|
const EnumValueDescriptor *vd = descriptor_->value(index);
|
|
|
|
map<string, string> vars;
|
|
|
|
vars["enum_value_name"] = vd->name();
|
protoc-c: preserve case in C enum value names (Issue #129)
there is some confusion with regard to the use of lower case letters in
enum values. take the following message definition:
message LowerCase {
enum CaseEnum {
UPPER = 1;
lower = 2;
}
optional CaseEnum value = 1 [default = lower];
}
this generates the following C enum:
typedef enum _LowerCase__CaseEnum {
LOWER_CASE__CASE_ENUM__UPPER = 1,
LOWER_CASE__CASE_ENUM__lower = 2
_PROTOBUF_C_FORCE_ENUM_TO_BE_INT_SIZE(LOWER_CASE__CASE_ENUM)
} LowerCase__CaseEnum;
note that the case of the enum value 'lower' was preserved in the C
symbol name as 'LOWER_CASE__CASE_ENUM__lower', but that the _INIT macro
references the same enum value with the (non-existent) C symbol name
'LOWER_CASE__CASE_ENUM__LOWER':
#define LOWER_CASE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&lower_case__descriptor) \
, 0,LOWER_CASE__CASE_ENUM__LOWER }
additionally, the ProtobufCEnumValue array generated also refers to the
same enum value with the (non-existent) upper cased version:
const ProtobufCEnumValue lower_case__case_enum__enum_values_by_number[2] =
{
{ "UPPER", "LOWER_CASE__CASE_ENUM__UPPER", 1 },
{ "lower", "LOWER_CASE__CASE_ENUM__LOWER", 2 },
};
we should preserve the existing behavior of copying the case from the
enum values in the message definition and fix up the places where the
(non-existent) upper case version is used, rather than changing the enum
definition itself to match the case used in the _INIT macro and
enum_values_by_number array, because it's possible that there might be
existing working code that uses enum values with lower case letters that
would be affected by such a change.
incidentally, google's C++ protobuf implementation preserves case in
enum values. protoc --cpp_out generates the following enum declaration
for the message descriptor above:
enum LowerCase_CaseEnum {
LowerCase_CaseEnum_UPPER = 1,
LowerCase_CaseEnum_lower = 2
};
2014-03-24 15:43:53 -04:00
|
|
|
vars["c_enum_value_name"] = FullNameToUpper(descriptor_->full_name()) + "__" + vd->name();
|
2008-08-22 20:38:05 +00:00
|
|
|
vars["value"] = SimpleItoa(vd->number());
|
|
|
|
printer->Print(vars,
|
|
|
|
" { \"$enum_value_name$\", \"$c_enum_value_name$\", $value$ },\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_value_indices_by_value_then_index(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const ValueIndex *vi_a = (const ValueIndex *) a;
|
|
|
|
const ValueIndex *vi_b = (const ValueIndex *) b;
|
|
|
|
if (vi_a->value < vi_b->value) return -1;
|
|
|
|
if (vi_a->value > vi_b->value) return +1;
|
|
|
|
if (vi_a->index < vi_b->index) return -1;
|
|
|
|
if (vi_a->index > vi_b->index) return +1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-27 02:14:42 +00:00
|
|
|
static int compare_value_indices_by_name(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const ValueIndex *vi_a = (const ValueIndex *) a;
|
|
|
|
const ValueIndex *vi_b = (const ValueIndex *) b;
|
|
|
|
return strcmp (vi_a->name, vi_b->name);
|
|
|
|
}
|
|
|
|
|
2008-08-22 20:38:05 +00:00
|
|
|
void EnumGenerator::GenerateEnumDescriptor(io::Printer* printer) {
|
|
|
|
map<string, string> vars;
|
|
|
|
vars["fullname"] = descriptor_->full_name();
|
|
|
|
vars["lcclassname"] = FullNameToLower(descriptor_->full_name());
|
|
|
|
vars["cname"] = FullNameToC(descriptor_->full_name());
|
|
|
|
vars["shortname"] = descriptor_->name();
|
|
|
|
vars["packagename"] = descriptor_->file()->package();
|
|
|
|
vars["value_count"] = SimpleItoa(descriptor_->value_count());
|
|
|
|
|
|
|
|
// Sort by name and value, dropping duplicate values if they appear later.
|
|
|
|
// TODO: use a c++ paradigm for this!
|
|
|
|
NameIndex *name_index = new NameIndex[descriptor_->value_count()];
|
|
|
|
ValueIndex *value_index = new ValueIndex[descriptor_->value_count()];
|
|
|
|
for (int j = 0; j < descriptor_->value_count(); j++) {
|
|
|
|
const EnumValueDescriptor *vd = descriptor_->value(j);
|
|
|
|
name_index[j].index = j;
|
|
|
|
name_index[j].name = vd->name().c_str();
|
|
|
|
value_index[j].index = j;
|
|
|
|
value_index[j].value = vd->number();
|
2008-08-27 02:14:42 +00:00
|
|
|
value_index[j].name = vd->name().c_str();
|
2008-08-22 20:38:05 +00:00
|
|
|
}
|
|
|
|
qsort(value_index, descriptor_->value_count(),
|
|
|
|
sizeof(ValueIndex), compare_value_indices_by_value_then_index);
|
|
|
|
|
|
|
|
// only record unique values
|
|
|
|
int n_unique_values;
|
|
|
|
if (descriptor_->value_count() == 0) {
|
|
|
|
n_unique_values = 0; // should never happen
|
|
|
|
} else {
|
|
|
|
n_unique_values = 1;
|
2008-08-27 02:14:42 +00:00
|
|
|
value_index[0].final_index = 0;
|
2008-08-22 20:38:05 +00:00
|
|
|
for (int j = 1; j < descriptor_->value_count(); j++) {
|
|
|
|
if (value_index[j-1].value != value_index[j].value)
|
2008-08-27 02:14:42 +00:00
|
|
|
value_index[j].final_index = n_unique_values++;
|
|
|
|
else
|
|
|
|
value_index[j].final_index = n_unique_values - 1;
|
2008-08-22 20:38:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vars["unique_value_count"] = SimpleItoa(n_unique_values);
|
|
|
|
printer->Print(vars,
|
2008-08-27 02:14:42 +00:00
|
|
|
"const ProtobufCEnumValue $lcclassname$__enum_values_by_number[$unique_value_count$] =\n"
|
2008-08-22 20:38:05 +00:00
|
|
|
"{\n");
|
|
|
|
if (descriptor_->value_count() > 0) {
|
|
|
|
GenerateValueInitializer(printer, value_index[0].index);
|
|
|
|
for (int j = 1; j < descriptor_->value_count(); j++) {
|
|
|
|
if (value_index[j-1].value != value_index[j].value) {
|
|
|
|
GenerateValueInitializer(printer, value_index[j].index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printer->Print(vars, "};\n");
|
2008-08-27 02:14:42 +00:00
|
|
|
printer->Print(vars, "static const ProtobufCIntRange $lcclassname$__value_ranges[] = {\n");
|
|
|
|
unsigned n_ranges = 0;
|
|
|
|
if (descriptor_->value_count() > 0) {
|
|
|
|
unsigned range_start = 0;
|
|
|
|
unsigned range_len = 1;
|
2013-12-16 23:59:14 -08:00
|
|
|
int range_start_value = value_index[0].value;
|
|
|
|
int last_value = range_start_value;
|
2008-08-27 02:14:42 +00:00
|
|
|
for (int j = 1; j < descriptor_->value_count(); j++) {
|
|
|
|
if (value_index[j-1].value != value_index[j].value) {
|
|
|
|
if (last_value + 1 == value_index[j].value) {
|
|
|
|
range_len++;
|
|
|
|
} else {
|
|
|
|
// output range
|
|
|
|
vars["range_start_value"] = SimpleItoa(range_start_value);
|
|
|
|
vars["orig_index"] = SimpleItoa(range_start);
|
|
|
|
printer->Print (vars, "{$range_start_value$, $orig_index$},");
|
|
|
|
range_start_value = value_index[j].value;
|
|
|
|
range_start += range_len;
|
|
|
|
range_len = 1;
|
|
|
|
n_ranges++;
|
|
|
|
}
|
|
|
|
last_value = value_index[j].value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
vars["range_start_value"] = SimpleItoa(range_start_value);
|
|
|
|
vars["orig_index"] = SimpleItoa(range_start);
|
|
|
|
printer->Print (vars, "{$range_start_value$, $orig_index$},");
|
|
|
|
range_start += range_len;
|
|
|
|
n_ranges++;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
vars["range_start_value"] = SimpleItoa(0);
|
|
|
|
vars["orig_index"] = SimpleItoa(range_start);
|
|
|
|
printer->Print (vars, "{$range_start_value$, $orig_index$}\n};\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vars["n_ranges"] = SimpleItoa(n_ranges);
|
2008-08-22 20:38:05 +00:00
|
|
|
|
2008-08-27 02:14:42 +00:00
|
|
|
qsort(value_index, descriptor_->value_count(),
|
|
|
|
sizeof(ValueIndex), compare_value_indices_by_name);
|
2008-08-22 20:38:05 +00:00
|
|
|
printer->Print(vars,
|
2008-08-27 02:14:42 +00:00
|
|
|
"const ProtobufCEnumValueIndex $lcclassname$__enum_values_by_name[$value_count$] =\n"
|
2008-08-22 20:38:05 +00:00
|
|
|
"{\n");
|
|
|
|
for (int j = 0; j < descriptor_->value_count(); j++) {
|
2008-08-27 02:14:42 +00:00
|
|
|
vars["index"] = SimpleItoa(value_index[j].final_index);
|
|
|
|
vars["name"] = value_index[j].name;
|
|
|
|
printer->Print (vars, " { \"$name$\", $index$ },\n");
|
2008-08-22 20:38:05 +00:00
|
|
|
}
|
|
|
|
printer->Print(vars, "};\n");
|
|
|
|
|
|
|
|
printer->Print(vars,
|
|
|
|
"const ProtobufCEnumDescriptor $lcclassname$__descriptor =\n"
|
|
|
|
"{\n"
|
2014-06-04 17:17:15 -04:00
|
|
|
" PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n"
|
2008-08-22 20:38:05 +00:00
|
|
|
" \"$fullname$\",\n"
|
|
|
|
" \"$shortname$\",\n"
|
|
|
|
" \"$cname$\",\n"
|
|
|
|
" \"$packagename$\",\n"
|
|
|
|
" $unique_value_count$,\n"
|
2008-08-27 02:14:42 +00:00
|
|
|
" $lcclassname$__enum_values_by_number,\n"
|
2008-08-22 20:38:05 +00:00
|
|
|
" $value_count$,\n"
|
2008-08-27 02:14:42 +00:00
|
|
|
" $lcclassname$__enum_values_by_name,\n"
|
|
|
|
" $n_ranges$,\n"
|
2008-11-30 15:07:39 +00:00
|
|
|
" $lcclassname$__value_ranges,\n"
|
|
|
|
" NULL,NULL,NULL,NULL /* reserved[1234] */\n"
|
2008-08-22 20:38:05 +00:00
|
|
|
"};\n");
|
2014-01-11 15:40:27 -05:00
|
|
|
|
2014-01-11 15:42:24 -05:00
|
|
|
delete[] value_index;
|
2014-01-11 15:40:27 -05:00
|
|
|
delete[] name_index;
|
2008-08-22 20:38:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace c
|
|
|
|
} // namespace compiler
|
|
|
|
} // namespace protobuf
|
|
|
|
} // namespace google
|