1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31// Author: kenton@google.com (Kenton Varda) 32 33#include <google/protobuf/compiler/plugin.h> 34 35#include <iostream> 36#include <set> 37 38#ifdef _WIN32 39#include <io.h> 40#include <fcntl.h> 41#ifndef STDIN_FILENO 42#define STDIN_FILENO 0 43#endif 44#ifndef STDOUT_FILENO 45#define STDOUT_FILENO 1 46#endif 47#else 48#include <unistd.h> 49#endif 50 51#include <google/protobuf/stubs/logging.h> 52#include <google/protobuf/stubs/common.h> 53#include <google/protobuf/compiler/plugin.pb.h> 54#include <google/protobuf/compiler/code_generator.h> 55#include <google/protobuf/descriptor.h> 56#include <google/protobuf/io/zero_copy_stream_impl.h> 57 58 59namespace google { 60namespace protobuf { 61namespace compiler { 62 63class GeneratorResponseContext : public GeneratorContext { 64 public: 65 GeneratorResponseContext(CodeGeneratorResponse* response, 66 const vector<const FileDescriptor*>& parsed_files) 67 : response_(response), 68 parsed_files_(parsed_files) {} 69 virtual ~GeneratorResponseContext() {} 70 71 // implements GeneratorContext -------------------------------------- 72 73 virtual io::ZeroCopyOutputStream* Open(const string& filename) { 74 CodeGeneratorResponse::File* file = response_->add_file(); 75 file->set_name(filename); 76 return new io::StringOutputStream(file->mutable_content()); 77 } 78 79 virtual io::ZeroCopyOutputStream* OpenForInsert( 80 const string& filename, const string& insertion_point) { 81 CodeGeneratorResponse::File* file = response_->add_file(); 82 file->set_name(filename); 83 file->set_insertion_point(insertion_point); 84 return new io::StringOutputStream(file->mutable_content()); 85 } 86 87 void ListParsedFiles(vector<const FileDescriptor*>* output) { 88 *output = parsed_files_; 89 } 90 91 private: 92 CodeGeneratorResponse* response_; 93 const vector<const FileDescriptor*>& parsed_files_; 94}; 95 96bool GenerateCode(const CodeGeneratorRequest& request, 97 const CodeGenerator& generator, CodeGeneratorResponse* response, 98 string* error_msg) { 99 DescriptorPool pool; 100 for (int i = 0; i < request.proto_file_size(); i++) { 101 const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); 102 if (file == NULL) { 103 // BuildFile() already wrote an error message. 104 return false; 105 } 106 } 107 108 vector<const FileDescriptor*> parsed_files; 109 for (int i = 0; i < request.file_to_generate_size(); i++) { 110 parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); 111 if (parsed_files.back() == NULL) { 112 *error_msg = "protoc asked plugin to generate a file but " 113 "did not provide a descriptor for the file: " + 114 request.file_to_generate(i); 115 return false; 116 } 117 } 118 119 GeneratorResponseContext context(response, parsed_files); 120 121 if (generator.HasGenerateAll()) { 122 string error; 123 bool succeeded = generator.GenerateAll( 124 parsed_files, request.parameter(), &context, &error); 125 126 if (!succeeded && error.empty()) { 127 error = "Code generator returned false but provided no error " 128 "description."; 129 } 130 if (!error.empty()) { 131 response->set_error(error); 132 } 133 } else { 134 for (int i = 0; i < parsed_files.size(); i++) { 135 const FileDescriptor* file = parsed_files[i]; 136 137 string error; 138 bool succeeded = generator.Generate( 139 file, request.parameter(), &context, &error); 140 141 if (!succeeded && error.empty()) { 142 error = "Code generator returned false but provided no error " 143 "description."; 144 } 145 if (!error.empty()) { 146 response->set_error(file->name() + ": " + error); 147 break; 148 } 149 } 150 } 151 152 return true; 153} 154 155int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { 156 157 if (argc > 1) { 158 std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl; 159 return 1; 160 } 161 162#ifdef _WIN32 163 _setmode(STDIN_FILENO, _O_BINARY); 164 _setmode(STDOUT_FILENO, _O_BINARY); 165#endif 166 167 CodeGeneratorRequest request; 168 if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { 169 std::cerr << argv[0] << ": protoc sent unparseable request to plugin." 170 << std::endl; 171 return 1; 172 } 173 174 string error_msg; 175 CodeGeneratorResponse response; 176 177 if (GenerateCode(request, *generator, &response, &error_msg)) { 178 if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { 179 std::cerr << argv[0] << ": Error writing to stdout." << std::endl; 180 return 1; 181 } 182 } else { 183 if (!error_msg.empty()) { 184 std::cerr << argv[0] << ": " << error_msg << std::endl; 185 } 186 return 1; 187 } 188 189 return 0; 190} 191 192} // namespace compiler 193} // namespace protobuf 194} // namespace google 195