diff options
author | Thomas Van Lenten <thomasvl@google.com> | 2016-06-17 10:31:05 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-17 10:31:05 -0400 |
commit | 8c20e55c57c90a1a84ac7cf4de96e65911c8212b (patch) | |
tree | 0682f0331cefbe005f0d4e215e487d3179494516 /src/google/protobuf/compiler/objectivec/objectivec_helpers.cc | |
parent | 98bd6d753a2b15774c56ecd49763ceb2820d7075 (diff) |
Add new generation option for using proto sources from other frameworks.
- Better docs in the generator for the different options that can be passed
during an invoke of protoc.
- Add named_framework_to_proto_path_mappings_path to pass the path to a file
containing mappings of frameworks for different proto files.
- Update the generation to use the mapping to change the #import directives
it creates.
Note: the changes in helpers is mostly moving code within the fine, and then
a small change to expose the parsing so a passed on class can consume the line.
Fixes https://github.com/google/protobuf/issues/1457
Diffstat (limited to 'src/google/protobuf/compiler/objectivec/objectivec_helpers.cc')
-rw-r--r-- | src/google/protobuf/compiler/objectivec/objectivec_helpers.cc | 279 |
1 files changed, 159 insertions, 120 deletions
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 65bf8348..311bf35d 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -81,6 +81,10 @@ const char* const kUpperSegmentsList[] = {"url", "http", "https"}; hash_set<string> kUpperSegments = MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList)); +bool ascii_isnewline(char c) { + return c == '\n' || c == '\r'; +} + // Internal helper for name handing. // Do not expose this outside of helpers, stick to having functions for specific // cases (ClassName(), FieldName()), so there is always consistent suffix rules. @@ -272,6 +276,16 @@ string StripProto(const string& filename) { } } +void StringPieceTrimWhitespace(StringPiece* input) { + while (!input->empty() && ascii_isspace(*input->data())) { + input->remove_prefix(1); + } + while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) { + input->remove_suffix(1); + } +} + + bool IsRetainedName(const string& name) { // List of prefixes from // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html @@ -871,65 +885,6 @@ bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { return false; } -namespace { - -// Internal helper class that parses the expected package to prefix mappings -// file. -class Parser { - public: - Parser(map<string, string>* inout_package_to_prefix_map) - : prefix_map_(inout_package_to_prefix_map), line_(0) {} - - // Parses a check of input, returning success/failure. - bool ParseChunk(StringPiece chunk); - - // Should be called to finish parsing (after all input has been provided via - // ParseChunk()). Returns success/failure. - bool Finish(); - - int last_line() const { return line_; } - string error_str() const { return error_str_; } - - private: - bool ParseLoop(); - - map<string, string>* prefix_map_; - int line_; - string error_str_; - StringPiece p_; - string leftover_; -}; - -bool Parser::ParseChunk(StringPiece chunk) { - if (!leftover_.empty()) { - chunk.AppendToString(&leftover_); - p_ = StringPiece(leftover_); - } else { - p_ = chunk; - } - bool result = ParseLoop(); - if (p_.empty()) { - leftover_.clear(); - } else { - leftover_ = p_.ToString(); - } - return result; -} - -bool Parser::Finish() { - if (leftover_.empty()) { - return true; - } - // Force a newline onto the end to finish parsing. - p_ = StringPiece(leftover_ + "\n"); - if (!ParseLoop()) { - return false; - } - return p_.empty(); // Everything used? -} - -static bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; } - bool ReadLine(StringPiece* input, StringPiece* line) { for (int len = 0; len < input->size(); ++len) { if (ascii_isnewline((*input)[len])) { @@ -942,15 +897,6 @@ bool ReadLine(StringPiece* input, StringPiece* line) { return false; // Ran out of input with no newline. } -void TrimWhitespace(StringPiece* input) { - while (!input->empty() && ascii_isspace(*input->data())) { - input->remove_prefix(1); - } - while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) { - input->remove_suffix(1); - } -} - void RemoveComment(StringPiece* input) { int offset = input->find('#'); if (offset != StringPiece::npos) { @@ -958,29 +904,35 @@ void RemoveComment(StringPiece* input) { } } -bool Parser::ParseLoop() { - StringPiece line; - while (ReadLine(&p_, &line)) { - ++line_; - RemoveComment(&line); - TrimWhitespace(&line); - if (line.size() == 0) { - continue; // Blank line. - } - int offset = line.find('='); - if (offset == StringPiece::npos) { - error_str_ = - string("Line without equal sign: '") + line.ToString() + "'."; - return false; - } - StringPiece package(line, 0, offset); - StringPiece prefix(line, offset + 1, line.length() - offset - 1); - TrimWhitespace(&package); - TrimWhitespace(&prefix); - // Don't really worry about error checking the package/prefix for - // being valid. Assume the file is validated when it is created/edited. - (*prefix_map_)[package.ToString()] = prefix.ToString(); +namespace { + +class ExpectedPrefixesCollector : public LineConsumer { + public: + ExpectedPrefixesCollector(map<string, string>* inout_package_to_prefix_map) + : prefix_map_(inout_package_to_prefix_map) {} + + virtual bool ConsumeLine(const StringPiece& line, string* out_error); + + private: + map<string, string>* prefix_map_; +}; + +bool ExpectedPrefixesCollector::ConsumeLine( + const StringPiece& line, string* out_error) { + int offset = line.find('='); + if (offset == StringPiece::npos) { + *out_error = + string("Expected prefixes file line without equal sign: '") + + line.ToString() + "'."; + return false; } + StringPiece package(line, 0, offset); + StringPiece prefix(line, offset + 1, line.length() - offset - 1); + StringPieceTrimWhitespace(&package); + StringPieceTrimWhitespace(&prefix); + // Don't really worry about error checking the package/prefix for + // being valid. Assume the file is validated when it is created/edited. + (*prefix_map_)[package.ToString()] = prefix.ToString(); return true; } @@ -991,36 +943,9 @@ bool LoadExpectedPackagePrefixes(const Options &generation_options, return true; } - int fd; - do { - fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY); - } while (fd < 0 && errno == EINTR); - if (fd < 0) { - *out_error = - string("error: Unable to open \"") + - generation_options.expected_prefixes_path + - "\", " + strerror(errno); - return false; - } - io::FileInputStream file_stream(fd); - file_stream.SetCloseOnDelete(true); - - Parser parser(prefix_map); - const void* buf; - int buf_len; - while (file_stream.Next(&buf, &buf_len)) { - if (buf_len == 0) { - continue; - } - - if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) { - *out_error = - string("error: ") + generation_options.expected_prefixes_path + - " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str(); - return false; - } - } - return parser.Finish(); + ExpectedPrefixesCollector collector(prefix_map); + return ParseSimpleFile( + generation_options.expected_prefixes_path, &collector, out_error); } } // namespace @@ -1121,6 +1046,10 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, return true; } +TextFormatDecodeData::TextFormatDecodeData() { } + +TextFormatDecodeData::~TextFormatDecodeData() { } + void TextFormatDecodeData::AddString(int32 key, const string& input_for_decode, const string& desired_output) { @@ -1329,6 +1258,116 @@ string TextFormatDecodeData::DecodeDataForString(const string& input_for_decode, return builder.Finish() + (char)'\0'; } +namespace { + +class Parser { + public: + Parser(LineConsumer* line_consumer) + : line_consumer_(line_consumer), line_(0) {} + + // Parses a check of input, returning success/failure. + bool ParseChunk(StringPiece chunk); + + // Should be called to finish parsing (after all input has been provided via + // ParseChunk()). Returns success/failure. + bool Finish(); + + int last_line() const { return line_; } + string error_str() const { return error_str_; } + + private: + bool ParseLoop(); + + LineConsumer* line_consumer_; + int line_; + string error_str_; + StringPiece p_; + string leftover_; +}; + +bool Parser::ParseChunk(StringPiece chunk) { + if (!leftover_.empty()) { + chunk.AppendToString(&leftover_); + p_ = StringPiece(leftover_); + } else { + p_ = chunk; + } + bool result = ParseLoop(); + if (p_.empty()) { + leftover_.clear(); + } else { + leftover_ = p_.ToString(); + } + return result; +} + +bool Parser::Finish() { + if (leftover_.empty()) { + return true; + } + // Force a newline onto the end to finish parsing. + p_ = StringPiece(leftover_ + "\n"); + if (!ParseLoop()) { + return false; + } + return p_.empty(); // Everything used? +} + +bool Parser::ParseLoop() { + StringPiece line; + while (ReadLine(&p_, &line)) { + ++line_; + RemoveComment(&line); + StringPieceTrimWhitespace(&line); + if (line.size() == 0) { + continue; // Blank line. + } + if (!line_consumer_->ConsumeLine(line, &error_str_)) { + return false; + } + } + return true; +} + +} // namespace + +LineConsumer::LineConsumer() {} + +LineConsumer::~LineConsumer() {} + +bool ParseSimpleFile( + const string& path, LineConsumer* line_consumer, string* out_error) { + int fd; + do { + fd = open(path.c_str(), O_RDONLY); + } while (fd < 0 && errno == EINTR); + if (fd < 0) { + *out_error = + string("error: Unable to open \"") + path + "\", " + strerror(errno); + return false; + } + io::FileInputStream file_stream(fd); + file_stream.SetCloseOnDelete(true); + + Parser parser(line_consumer); + const void* buf; + int buf_len; + while (file_stream.Next(&buf, &buf_len)) { + if (buf_len == 0) { + continue; + } + + if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) { + *out_error = + string("error: ") + path + + " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str(); + return false; + } + } + return parser.Finish(); +} + + } // namespace objectivec } // namespace compiler } // namespace protobuf |