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/common.h> 52#include <google/protobuf/compiler/plugin.pb.h> 53#include <google/protobuf/compiler/code_generator.h> 54#include <google/protobuf/descriptor.h> 55#include <google/protobuf/io/zero_copy_stream_impl.h> 56 57 58namespace google { 59namespace protobuf { 60namespace compiler { 61 62class GeneratorResponseContext : public GeneratorContext { 63 public: 64 GeneratorResponseContext(CodeGeneratorResponse* response, 65 const vector<const FileDescriptor*>& parsed_files) 66 : response_(response), 67 parsed_files_(parsed_files) {} 68 virtual ~GeneratorResponseContext() {} 69 70 // implements GeneratorContext -------------------------------------- 71 72 virtual io::ZeroCopyOutputStream* Open(const string& filename) { 73 CodeGeneratorResponse::File* file = response_->add_file(); 74 file->set_name(filename); 75 return new io::StringOutputStream(file->mutable_content()); 76 } 77 78 virtual io::ZeroCopyOutputStream* OpenForInsert( 79 const string& filename, const string& insertion_point) { 80 CodeGeneratorResponse::File* file = response_->add_file(); 81 file->set_name(filename); 82 file->set_insertion_point(insertion_point); 83 return new io::StringOutputStream(file->mutable_content()); 84 } 85 86 void ListParsedFiles(vector<const FileDescriptor*>* output) { 87 *output = parsed_files_; 88 } 89 90 private: 91 CodeGeneratorResponse* response_; 92 const vector<const FileDescriptor*>& parsed_files_; 93}; 94 95int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { 96 97 if (argc > 1) { 98 cerr << argv[0] << ": Unknown option: " << argv[1] << endl; 99 return 1; 100 } 101 102#ifdef _WIN32 103 _setmode(STDIN_FILENO, _O_BINARY); 104 _setmode(STDOUT_FILENO, _O_BINARY); 105#endif 106 107 CodeGeneratorRequest request; 108 if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { 109 cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl; 110 return 1; 111 } 112 113 DescriptorPool pool; 114 for (int i = 0; i < request.proto_file_size(); i++) { 115 const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); 116 if (file == NULL) { 117 // BuildFile() already wrote an error message. 118 return 1; 119 } 120 } 121 122 vector<const FileDescriptor*> parsed_files; 123 for (int i = 0; i < request.file_to_generate_size(); i++) { 124 parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); 125 if (parsed_files.back() == NULL) { 126 cerr << argv[0] << ": protoc asked plugin to generate a file but " 127 "did not provide a descriptor for the file: " 128 << request.file_to_generate(i) << endl; 129 return 1; 130 } 131 } 132 133 CodeGeneratorResponse response; 134 GeneratorResponseContext context(&response, parsed_files); 135 136 for (int i = 0; i < parsed_files.size(); i++) { 137 const FileDescriptor* file = parsed_files[i]; 138 139 string error; 140 bool succeeded = generator->Generate( 141 file, request.parameter(), &context, &error); 142 143 if (!succeeded && error.empty()) { 144 error = "Code generator returned false but provided no error " 145 "description."; 146 } 147 if (!error.empty()) { 148 response.set_error(file->name() + ": " + error); 149 break; 150 } 151 } 152 153 if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { 154 cerr << argv[0] << ": Error writing to stdout." << endl; 155 return 1; 156 } 157 158 return 0; 159} 160 161} // namespace compiler 162} // namespace protobuf 163} // namespace google 164