aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/compiler/command_line_interface.cc
diff options
context:
space:
mode:
authorjieluo@google.com <jieluo@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2014-07-18 00:47:59 +0000
committerjieluo@google.com <jieluo@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2014-07-18 00:47:59 +0000
commit4de8f55113007fdc8e34107950e605fc0209d465 (patch)
tree92b7da8757a7740d9e1f2d3ead233542947d8c8c /src/google/protobuf/compiler/command_line_interface.cc
parentc5553a3d18f80132b9079c5504bc0aa1f7f950a0 (diff)
downloadprotobuf-4de8f55113007fdc8e34107950e605fc0209d465.tar.gz
protobuf-4de8f55113007fdc8e34107950e605fc0209d465.tar.bz2
protobuf-4de8f55113007fdc8e34107950e605fc0209d465.zip
down integrate to svn
Diffstat (limited to 'src/google/protobuf/compiler/command_line_interface.cc')
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc194
1 files changed, 180 insertions, 14 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index b9293c97..358d6462 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -49,8 +49,10 @@
#include <ctype.h>
#include <google/protobuf/stubs/hash.h>
+#include <memory>
#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/plugin.pb.h>
@@ -64,7 +66,7 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
-#include <google/protobuf/stubs/map-util.h>
+#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/stl_util.h>
@@ -160,8 +162,7 @@ bool VerifyDirectoryExists(const string& path) {
// directories listed in |filename|.
bool TryCreateParentDirectory(const string& prefix, const string& filename) {
// Recursively create parent directories to the output file.
- vector<string> parts;
- SplitStringUsing(filename, "/", &parts);
+ vector<string> parts = Split(filename, "/", true);
string path_so_far = prefix;
for (int i = 0; i < parts.size() - 1; i++) {
path_so_far += parts[i];
@@ -252,6 +253,7 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
// implements GeneratorContext --------------------------------------
io::ZeroCopyOutputStream* Open(const string& filename);
+ io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
io::ZeroCopyOutputStream* OpenForInsert(
const string& filename, const string& insertion_point);
void ListParsedFiles(vector<const FileDescriptor*>* output) {
@@ -271,7 +273,8 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
class CommandLineInterface::MemoryOutputStream
: public io::ZeroCopyOutputStream {
public:
- MemoryOutputStream(GeneratorContextImpl* directory, const string& filename);
+ MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
+ bool append_mode);
MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
const string& insertion_point);
virtual ~MemoryOutputStream();
@@ -290,6 +293,9 @@ class CommandLineInterface::MemoryOutputStream
// The string we're building.
string data_;
+ // Whether we should append the output stream to the existing file.
+ bool append_mode_;
+
// StringOutputStream writing to data_.
scoped_ptr<io::StringOutputStream> inner_;
};
@@ -434,7 +440,13 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
const string& filename) {
- return new MemoryOutputStream(this, filename);
+ return new MemoryOutputStream(this, filename, false);
+}
+
+io::ZeroCopyOutputStream*
+CommandLineInterface::GeneratorContextImpl::OpenForAppend(
+ const string& filename) {
+ return new MemoryOutputStream(this, filename, true);
}
io::ZeroCopyOutputStream*
@@ -446,9 +458,10 @@ CommandLineInterface::GeneratorContextImpl::OpenForInsert(
// -------------------------------------------------------------------
CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
- GeneratorContextImpl* directory, const string& filename)
+ GeneratorContextImpl* directory, const string& filename, bool append_mode)
: directory_(directory),
filename_(filename),
+ append_mode_(append_mode),
inner_(new io::StringOutputStream(&data_)) {
}
@@ -471,8 +484,12 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
if (insertion_point_.empty()) {
// This was just a regular Open().
if (*map_slot != NULL) {
- cerr << filename_ << ": Tried to write the same file twice." << endl;
- directory_->had_error_ = true;
+ if (append_mode_) {
+ (*map_slot)->append(data_);
+ } else {
+ cerr << filename_ << ": Tried to write the same file twice." << endl;
+ directory_->had_error_ = true;
+ }
return;
}
@@ -565,6 +582,7 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
CommandLineInterface::CommandLineInterface()
: mode_(MODE_COMPILE),
+ print_mode_(PRINT_NONE),
error_format_(ERROR_FORMAT_GCC),
imports_in_descriptor_set_(false),
source_info_in_descriptor_set_(false),
@@ -632,7 +650,9 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
// Parse each file.
for (int i = 0; i < input_files_.size(); i++) {
// Import the file.
+ importer.AddUnusedImportTrackFile(input_files_[i]);
const FileDescriptor* parsed_file = importer.Import(input_files_[i]);
+ importer.ClearUnusedImportTrackFiles();
if (parsed_file == NULL) return 1;
parsed_files.push_back(parsed_file);
@@ -721,6 +741,25 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}
}
+ if (mode_ == MODE_PRINT) {
+ switch (print_mode_) {
+ case PRINT_FREE_FIELDS:
+ for (int i = 0; i < parsed_files.size(); ++i) {
+ const FileDescriptor* fd = parsed_files[i];
+ for (int j = 0; j < fd->message_type_count(); ++j) {
+ PrintFreeFieldNumbers(fd->message_type(j));
+ }
+ }
+ break;
+ case PRINT_NONE:
+ GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of "
+ "flag parsing in the CommonadLineInterface.";
+ return 1;
+
+ // Do not add a default case.
+ }
+ }
+
return 0;
}
@@ -735,6 +774,7 @@ void CommandLineInterface::Clear() {
descriptor_set_name_.clear();
mode_ = MODE_COMPILE;
+ print_mode_ = PRINT_NONE;
imports_in_descriptor_set_ = false;
source_info_in_descriptor_set_ = false;
disallow_services_ = false;
@@ -889,7 +929,8 @@ bool CommandLineInterface::ParseArgument(const char* arg,
*name == "--include_imports" ||
*name == "--include_source_info" ||
*name == "--version" ||
- *name == "--decode_raw") {
+ *name == "--decode_raw" ||
+ *name == "--print_free_field_numbers") {
// HACK: These are the only flags that don't take a value.
// They probably should not be hard-coded like this but for now it's
// not worth doing better.
@@ -919,8 +960,8 @@ CommandLineInterface::InterpretArgument(const string& name,
// Java's -classpath (and some other languages) delimits path components
// with colons. Let's accept that syntax too just to make things more
// intuitive.
- vector<string> parts;
- SplitStringUsing(value, kPathSeparator, &parts);
+ vector<string> parts = Split(
+ value, kPathSeparator, true);
for (int i = 0; i < parts.size(); i++) {
string virtual_path;
@@ -1061,6 +1102,19 @@ CommandLineInterface::InterpretArgument(const string& name,
plugins_[plugin_name] = path;
+ } else if (name == "--print_free_field_numbers") {
+ if (mode_ != MODE_COMPILE) {
+ cerr << "Cannot use " << name << " and use --encode, --decode or print "
+ << "other info at the same time." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
+ cerr << "Cannot use " << name
+ << " and generate code or descriptors at the same time." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ mode_ = MODE_PRINT;
+ print_mode_ = PRINT_FREE_FIELDS;
} else {
// Some other flag. Look it up in the generators list.
const GeneratorInfo* generator_info =
@@ -1082,8 +1136,8 @@ CommandLineInterface::InterpretArgument(const string& name,
} else {
// It's an output flag. Add it to the output directives.
if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use --encode or --decode and generate code at the "
- "same time." << endl;
+ cerr << "Cannot use --encode, --decode or print .proto info and "
+ "generate code at the same time." << endl;
return PARSE_ARGUMENT_FAIL;
}
@@ -1151,7 +1205,12 @@ void CommandLineInterface::PrintHelpText() {
" well as surrounding comments.\n"
" --error_format=FORMAT Set the format in which to print errors.\n"
" FORMAT may be 'gcc' (the default) or 'msvs'\n"
-" (Microsoft Visual Studio format)." << endl;
+" (Microsoft Visual Studio format).\n"
+" --print_free_field_numbers Print the free field numbers of the messages\n"
+" defined in the given proto files. Groups share\n"
+" the same field number space with the parent \n"
+" message. Extension ranges are counted as \n"
+" occupied fields numbers." << endl;
if (!plugin_prefix_.empty()) {
cerr <<
" --plugin=EXECUTABLE Specifies a plugin executable to use.\n"
@@ -1431,6 +1490,113 @@ void CommandLineInterface::GetTransitiveDependencies(
}
}
+namespace {
+
+// Utility function for PrintFreeFieldNumbers.
+// Stores occupied ranges into the ranges parameter, and next level of sub
+// message types into the nested_messages parameter. The FieldRange is left
+// inclusive, right exclusive. i.e. [a, b).
+//
+// Nested Messages:
+// Note that it only stores the nested message type, iff the nested type is
+// either a direct child of the given descriptor, or the nested type is a
+// decendent of the given descriptor and all the nodes between the
+// nested type and the given descriptor are group types. e.g.
+//
+// message Foo {
+// message Bar {
+// message NestedBar {}
+// }
+// group Baz = 1 {
+// group NestedBazGroup = 2 {
+// message Quz {
+// message NestedQuz {}
+// }
+// }
+// message NestedBaz {}
+// }
+// }
+//
+// In this case, Bar, Quz and NestedBaz will be added into the nested types.
+// Since free field numbers of group types will not be printed, this makes sure
+// the nested message types in groups will not be dropped. The nested_messages
+// parameter will contain the direct children (when groups are ignored in the
+// tree) of the given descriptor for the caller to traverse. The declaration
+// order of the nested messages is also preserved.
+typedef pair<int, int> FieldRange;
+void GatherOccupiedFieldRanges(const Descriptor* descriptor,
+ set<FieldRange>* ranges,
+ vector<const Descriptor*>* nested_messages) {
+ set<const Descriptor*> groups;
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ const FieldDescriptor* fd = descriptor->field(i);
+ ranges->insert(FieldRange(fd->number(), fd->number() + 1));
+ if (fd->type() == FieldDescriptor::TYPE_GROUP) {
+ groups.insert(fd->message_type());
+ }
+ }
+ for (int i = 0; i < descriptor->extension_range_count(); ++i) {
+ ranges->insert(FieldRange(descriptor->extension_range(i)->start,
+ descriptor->extension_range(i)->end));
+ }
+ // Handle the nested messages/groups in declaration order to make it
+ // post-order strict.
+ for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+ const Descriptor* nested_desc = descriptor->nested_type(i);
+ if (groups.find(nested_desc) != groups.end()) {
+ GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
+ } else {
+ nested_messages->push_back(nested_desc);
+ }
+ }
+}
+
+// Utility function for PrintFreeFieldNumbers.
+// Actually prints the formatted free field numbers for given message name and
+// occupied ranges.
+void FormatFreeFieldNumbers(const string& name,
+ const set<FieldRange>& ranges) {
+ string output;
+ StringAppendF(&output, "%-35s free:", name.c_str());
+ int next_free_number = 1;
+ for (set<FieldRange>::iterator i = ranges.begin();
+ i != ranges.end(); ++i) {
+ // This happens when groups re-use parent field numbers, in which
+ // case we skip the FieldRange entirely.
+ if (next_free_number >= i->second) continue;
+
+ if (next_free_number < i->first) {
+ if (next_free_number + 1 == i->first) {
+ // Singleton
+ StringAppendF(&output, " %d", next_free_number);
+ } else {
+ // Range
+ StringAppendF(&output, " %d-%d", next_free_number, i->first - 1);
+ }
+ }
+ next_free_number = i->second;
+ }
+ if (next_free_number <= FieldDescriptor::kMaxNumber) {
+ StringAppendF(&output, " %d-INF", next_free_number);
+ }
+ cout << output << endl;
+}
+
+} // namespace
+
+void CommandLineInterface::PrintFreeFieldNumbers(
+ const Descriptor* descriptor) {
+ set<FieldRange> ranges;
+ vector<const Descriptor*> nested_messages;
+ GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
+
+ for (int i = 0; i < nested_messages.size(); ++i) {
+ PrintFreeFieldNumbers(nested_messages[i]);
+ }
+ FormatFreeFieldNumbers(descriptor->full_name(), ranges);
+}
+
+
} // namespace compiler
} // namespace protobuf